Argument scope

S

Stefan Ram

Here is an idea for a new scope in Java (could be
used in other languages as well):

void fill
( final int color
{ final int RED = 1;
final int GREEN = 2;
final int BLUE = 3; })
{ /* ... */ }

Now one can call this as, for example:

fill( GREEN );

But one does not need to write

fill( Class.GREEN );

or so anymore.

The scope of the identifier »GREEN« is only the
argument expression corresponding to the parameter
»color«. So GREEN is not recognized here:

final int i = GREEN; fill( i ); /* not supported */

If »Beta« is an interface, one can also write:

void fill( final int color import Beta ){ /* ... */ }

, to »import« the constants of the interface Beta for
this purpose.

Or, we could have an import for Enum types:

void test( final enum Day import ){ /* ... */ }

, so that one then can write

test( MONDAY )

instead of

test( Day.MONDAY )

.
 
T

Tom Anderson

Here is an idea for a new scope in Java (could be
used in other languages as well):

void fill
( final int color
{ final int RED = 1;
final int GREEN = 2;
final int BLUE = 3; })
{ /* ... */ }

Now one can call this as, for example:

fill( GREEN );

But one does not need to write

fill( Class.GREEN );

or so anymore.

I'd quite like that. Ages ago, i had the idea of being able to write:

class Paintbucket {
public static final int GREEN = 1;
public void fill(int colour) {...}
}

Paintbucket p;
p.fill(.GREEN);
// ^ leading dot indicates use of receiver scope

Static imports have made both our ideas somewhat redundant, though.

I also want a SmallTalk-inspired 'call this method on the same object as
the last statement' construct, which i'd also do with a leading dot:

BufferedWriter invoiceWriter;
invoiceWriter.writer(total);
..newLine();
..write(tax);
..newLine();

tom
 
A

Arne Vajhøj

Here is an idea for a new scope in Java (could be
used in other languages as well):

void fill
( final int color
{ final int RED = 1;
final int GREEN = 2;
final int BLUE = 3; })
{ /* ... */ }

Now one can call this as, for example:

fill( GREEN );

But one does not need to write

fill( Class.GREEN );

or so anymore.

The scope of the identifier »GREEN« is only the
argument expression corresponding to the parameter
»color«. So GREEN is not recognized here:

final int i = GREEN; fill( i ); /* not supported */

If »Beta« is an interface, one can also write:

void fill( final int color import Beta ){ /* ... */ }

, to »import« the constants of the interface Beta for
this purpose.

Or, we could have an import for Enum types:

void test( final enum Day import ){ /* ... */ }

, so that one then can write

test( MONDAY )

instead of

test( Day.MONDAY )

There are actually two questions:
1) is this a feature that is useful?
2) is this feature so useful that it is worth adding
to the complexity of the language?

I would tend to say YES and NO.

Arne
 
C

ClassCastException

I also want a SmallTalk-inspired 'call this method on the same object as
the last statement' construct, which i'd also do with a leading dot:

BufferedWriter invoiceWriter;
invoiceWriter.writer(total);
.newLine();
.write(tax);
.newLine();

Another case where Clojure comes to the rescue:

(with-open [wr (BufferedWriter. source)]
(doto wr
(.write total)
(.newLine)
(.write tax)
(.newLine)))

It even has the same dot-method syntax. But Lisp parenthesization, so
(.write tax) instead of .write(tax).

As you can see, Clojure also has a handy shortcut for

BufferedWriter wr = new BufferedWriter(...);
try {
...
} finally {
wr.close();
}

and indeed it's easy to make a (with-open ...) like construct to scope
and release resources in general. It's like having C++'s RAII back, only
without the icky rest of C++. :)
 
L

Lew

ClassCastException said:
Another case where Clojure comes to the rescue:

(Clojure is the greatest shit since sliced bread)

It even has (really groovy shit).

As you can see, Clojure also (excels at saving the universe)

and indeed it's easy to make (everything beautiful) in general.
It's like having C++'s RAII back, only without the icky rest of C++. :)

But it is not Java.

Personally, I call "RAII" "RRID".

My personal "rescue" is just to type the extra lines of code. What, I'm going
to sprain my finger? At least I don't tar roofs for a living. That's an
honorable profession - those guys actually work for a living.
 
A

Andreas Leitgeb

ClassCastException said:
Another case where Clojure comes to the rescue:

If lisp-style is the rescue, I'd rather stay captured. :)
(Just my personal taste, not a judgement on clojure)

Btw., I do like Tom's suggestion ".addMeToo();", although
I think there could be cases where it wouldn't be obvious
to the reader of some code, which reference would really
be re-used. Also, it might impede insertion of trace-
logging code, as the following ".something()" would then
pick up the tracer object, instead.

If an object were designed for sequences of void method-calling,
then it should have its methods return "this", instead, so one
could do ref.callThis().callThat().callAnother(). ...
 
C

ClassCastException

Since you wrote the parenthesized expressions above, I take it you're a
convert? ;-)
Personally, I call "RAII" "RRID".

"Resource Release Is Destruction"?
My personal "rescue" is just to type the extra lines of code. What, I'm
going to sprain my finger? At least I don't tar roofs for a living.
That's an honorable profession - those guys actually work for a living.

One principle of sound software engineering is to try to specify each
fact in exactly one place -- cuts down on copy-paste errors and things
getting out of sync, not to mention saving typing, making code shorter
and more readable, and avoiding forgetting something the nth time you
reinvent wheel X.

Java lets you go pretty far with that with method and object
abstractions, but without macros and first-class functions it can not
quite get all the way there. Hence the repeated boilerplate Java code is
rife with, specifying over and over again how to "grab a stream, process
it, and then close it in an exception-safe manner" or "iterate over a
list removing some elements".

The with-open macro in Clojure addresses the former, however, and higher-
order functions combined with first-class functions and anonymous lambdas
take care of the latter. (The expression (remove #(= 0 %) foo) for
example returns a list that's a copy of foo with all the zeros removed;
if foo was (0 3 7 0 8) it gives (3 7 8) as its output. Clojure encourages
copying-with-modification in preference to in-place modification and
other thread-safe practices, though there are ways to do in-place
modification and you can even use the mutable java.util collections if
you really want to.)

As for how Java it is, it runs on the JVM, compiling to bytecodes; and
can use everything in Java's class library (except, IIRC, annotations,
support for which is forthcoming); so one might argue it's 2/3 Java.
(Others might argue that it's Java++. :))
 
C

ClassCastException

Btw., I do like Tom's suggestion ".addMeToo();", although
I think there could be cases where it wouldn't be obvious to the reader
of some code, which reference would really be re-used.

Clojure solves that too. :)

(doto x
(y z)
(w foo))

operates everything on x. If there's more than one possible referent
there'll be more dotos, and then you know to pay attention to the
parenthesis nesting level.
Also, it might impede insertion of trace- logging code, as the
following ".something()" would then pick up the tracer object, instead.

Decorator pattern to the rescue? Wrap the object itself in a decorator
that logs some of the method calls, then punts to the wrapped object.
Then the decorator grabs the .something() as well.

(Clojure version would be to wrap the function whose uses you want to
log, e.g. (def f #(binding [*out* log-out] (println "f" %1 %2) (f %1 %
2))) which will append "f x y\n" to log-out on the way to calling the
original f if you now call (f x y).
If an object were designed for sequences of void method-calling, then
it should have its methods return "this", instead, so one could do
ref.callThis().callThat().callAnother(). ...

I think there's a pattern name for this, too, and it's commonly employed
with factory objects.

FooFactory.withThis().withExtraSauce(42).withThat("quux").create();

and the like.
 
L

Lew

Since you wrote the parenthesized expressions above, I take it you're a
convert? ;-)

I was making fun of you. I expect to find you in an airport dressed in
saffron robes selling flowers to support Clojure.

Don't get me wrong - I find Krishna devotees to a person to be gentle,
sincere, deeply spiritual people.

Not so programming-language proselytes who pitch their off-topic spiel at the
merest hint of a whiff of a waft of aroma of possible relevance.

I do find it amusing, though.
 
C

ClassCastException

I was making fun of you. I expect to find you in an airport dressed in
saffron robes selling flowers to support Clojure.

Don't get me wrong - I find Krishna devotees to a person to be gentle,
sincere, deeply spiritual people.

Not so programming-language proselytes who pitch their off-topic spiel
at the merest hint of a whiff of a waft of aroma of possible relevance.

I do find it amusing, though.

Don't I get some bonus points for dissing C++?
 
L

Lew

ClassCastException said:
Don't I get some bonus points for dissing C++?

Of course. You even get bonus points for promoting Clojure. I am not against
the language by any means.
 
B

BGB

Here is an idea for a new scope in Java (could be
used in other languages as well):

void fill
( final int color
{ final int RED = 1;
final int GREEN = 2;
final int BLUE = 3; })
{ /* ... */ }

Now one can call this as, for example:

fill( GREEN );

But one does not need to write

fill( Class.GREEN );

or so anymore.

The scope of the identifier »GREEN« is only the
argument expression corresponding to the parameter
»color«. So GREEN is not recognized here:

final int i = GREEN; fill( i ); /* not supported */

If »Beta« is an interface, one can also write:

void fill( final int color import Beta ){ /* ... */ }

, to »import« the constants of the interface Beta for
this purpose.

Or, we could have an import for Enum types:

void test( final enum Day import ){ /* ... */ }

, so that one then can write

test( MONDAY )

instead of

test( Day.MONDAY )

.

in certain other languages, this is closer to the default behavior for
enum...

enum Color { RED=1, GREEN=2, BLUE=3 };

Color x;
x=RED;

with the compiler essentially figuring out what was meant by this
(nevermind a few semantic subtleties here...).



now, it may come as a bit if controversy here, but there are many common
tasks which prove a bit more awkward in Java than in its main
competitors (C, C++, C#, ...).

ability to most easily and efficiently express ideas is not one of the
high points of the language.

not that it is all that bad, but in a few ways they took the "thow the
baby out with the bathwater" strategy to language design (IOW, throwing
out many language features deemed "complicated" or "unsafe" at the cost
of making the language more awkward to use), and then tried apparently
to build elaborate class libraries to try to mask over some of the
weaknesses in the core language.

now, in everything there are costs and benefits...


yes, C is a little crufty, and many practices traditionally associated
with it are a subject of criticism (such as aversion to GC, or
overuse/abuse of pointer arithmetic, or for that matter coding practices
that don't scale well). these are not, however, inherent in the language.

yes, C++ is absurdly complex...

and yes, C# is mostly just a Java knock-off with some more C++ style
syntax and semantics reintroduced (nevermind traditional C-style
features re-introduced in different ways, such as via 'delegate' and 'ref').


I am torn at times...

I like the power of expression and fine level of control of C.
I like some of the added abstraction over the system of Java (and VM
architecture has some merits, although I disagree some with the
traditional overall architecture of the JVM).

I personally feel C# is a well designed language, but admittedly, I have
less warm and fuzzy feelings about .NET in general. (for my uses, .NET
was theoretically better, but I suspect more practically would have been
a worse investment).

ok... I am not so much of a fan of C++ though, its only real merit being
that it is close to C and has a good feature-set, but is at the same
time also a complex mess of cruft which I would rather not bother with
so much.


I guess this is why, although probably in the end somewhat pointless, I
tend to end up implementing my own compilers, languages and pieces of VM
technology.

even if implementations are only half-assed, at least I can do them my way.


although, I also tend to prefer trying for compatibility and standards
conformance where possible/reasonable, as in the end, the world already
has too many "YetAnotherLanguage" running on "YetAnotherVM" setups...

little is gained by more of the same...

hence, the current use of JVM architecture as a base.


and even if in the end all this is pointless and no one cares or
benefits, really why does this need to matter?


or such...
 
B

BGB

I was making fun of you. I expect to find you in an airport dressed in
saffron robes selling flowers to support Clojure.

Don't get me wrong - I find Krishna devotees to a person to be gentle,
sincere, deeply spiritual people.

Not so programming-language proselytes who pitch their off-topic spiel
at the merest hint of a whiff of a waft of aroma of possible relevance.

I do find it amusing, though.


hmm, yes, maybe I can be accused of this, grr...

although, admittedly, I don't believe as much in some "one true
language" so much as in the ideal of knocking down some of the walls
between them, many of which I feel are likely artificial and deliberate
(and others due to laziness or disinterest...).

"why should my new fancy language and VM have any reason to interop with
archaic C cruft?", or, "this language is so great that it doesn't need
interop, only everyone to see its greatness and adopt it as the one true
language", or, ...

I really dislike this sort of thinking (well, among other things, ...).


well, and trying to find decent ways to battle other long-lived problems
(namely, trying to find solutions which hopefully don't introduce more
problems than they solve).


the ideal solution may well be more in what things one doesn't see.

or such...
 
T

Tom Anderson

If lisp-style is the rescue, I'd rather stay captured. :) (Just my
personal taste, not a judgement on clojure)

Btw., I do like Tom's suggestion ".addMeToo();", although I think there
could be cases where it wouldn't be obvious to the reader of some code,
which reference would really be re-used.

That's my main worry about it. Perhaps we should instead steal something
from Delphi:

BufferedWriter out;
with (out) {
write("foo");
newLine();
write("bar");
newLine();
}

Which basically redefines the implicit target of invocations inside its
scope from 'this' to something else. It's a little wordier.

Going back to the original idea, perhaps you could mark the receiver:

StreamHolder holder;
[holder.getBufferedWriter()].write("foo"); .newLine(); .write("bar"); .newLine();

Although if the rule is otherwise that it's the leftmost term of the
top-level expression (not sure i'm expressing that right), then you could
just use normal parentheses there.
Also, it might impede insertion of trace- logging code, as the following
".something()" would then pick up the tracer object, instead.

True. The 'with' form avoids that too. But then i think this notation is
intended for small runs of tightly-coupled operations, where you probably
wouldn't want to log in between them. Still, it would be bound to trip
someone up sooner rather than later.
If an object were designed for sequences of void method-calling, then it
should have its methods return "this", instead, so one could do
ref.callThis().callThat().callAnother(). ...

A construction which i hate with a burning passion. Why on earth does the
append method of a StringBuffer return a StringBuffer? In what sense does
that method evaluate to a StringBuffer? How does that have any semantic
meaning? It's a perversion of the normal rules of method design to
accomodate a particular usage, which is unacceptably awful. The syntaxes
were kicking around are ways of enabling that compact style without
needing to pervert the design of code.

tom
 
L

Lew

Tom said:
Perhaps we should instead steal something from Delphi:

BufferedWriter out;
with (out) {
write("foo");
newLine();
write("bar");
newLine();
}

Which basically redefines the implicit target of invocations inside its
scope from 'this' to something else. It's a little wordier.

This is a great idea. It's no wordier than anything else in Java. OTOH it's
not backward compatible.

So the question becomes - how much value does this syntactic sugar provide,
and is it worth a language change? Is it worth two (or three) extra lines of
code and a language change to save a net negative fifteen characters?
 
B

BGB

That's my main worry about it. Perhaps we should instead steal something
from Delphi:

BufferedWriter out;
with (out) {
write("foo");
newLine();
write("bar");
newLine();
}

Which basically redefines the implicit target of invocations inside its
scope from 'this' to something else. It's a little wordier.

the above syntax I think exists in several other languages, such as
JavaScript and C# IIRC.

in my thinking, access rights should be preserved, so "with()" should
still not give access to any private or protected fields, ... (but, then
again I guess a proper JVM would enforce this restriction anyways).


admittedly, I would also like get/set support and structs, ... (if/when
I get around to finishing my Java compiler, I may support these as
language extensions...). at present it is a lower priority due to both
using standard compilers, and also having several other languages I also
make use of (my VM core also handles C and BGBScript at present).


get/set (AKA: properties) would just be syntax sugar, and probably with
a defined mapping to actual methods (probably "getX()"/"setX()" or
"get_x()"/"set_x()").

structs are still under some debate, mostly WRT how exactly to represent
and handle them in the VM (several related mechanisms were implemented).
I am now leaning towards handling them similar to normal Objects, with
them differing mostly in that they will use pass-by-value semantics.

likely implementation (current idle thinking):
they will be implemented as classes, which will be marked final and
likely inherit from "bgb/vm/Struct" (or "java/lang/struct", but this is
non-standard and "java/lang" is Sun/Oracle turf...);
potentially, semantics could be handled explicitly in the bytecode
(allowing potential standard-JVM compatibility).

hence, Struct would contain several special/magic methods:
"Z_clone()", copy struct;
"Z_set()", assign struct (copies all fields into a target struct of same
type);
"Z_free()", called when struct goes out of scope (likely no-op in
standard JVM).

(or "_Clone()", "_Set()", ... it is an open issue).


issues:
the above design would allow plain Java code (IOW: a standard compiler)
to access structs (possibly good), but plain Java would not necessarily
preserve correct semantics (bad).

a general-purpose "Z_clone()" and "Z_set()" would be expensive in a
standard JVM (would likely need to use reflection to implement them),
but are the most efficient for my VM (which would handle them
internally). struct types could overload these methods (to allow more
efficient handling by a standard JVM), but mine would likely ignore them
in this case (extending "Struct" will tell the VM that they are structs).

likely methods will be passed copies of structs (copy-in-caller), and
the called method will themselves be responsible for freeing them.

....

Going back to the original idea, perhaps you could mark the receiver:

StreamHolder holder;
[holder.getBufferedWriter()].write("foo"); .newLine(); .write("bar");
.newLine();

Although if the rule is otherwise that it's the leftmost term of the
top-level expression (not sure i'm expressing that right), then you
could just use normal parentheses there.

I don't like the above so much...

True. The 'with' form avoids that too. But then i think this notation is
intended for small runs of tightly-coupled operations, where you
probably wouldn't want to log in between them. Still, it would be bound
to trip someone up sooner rather than later.

yeah...

I like with() more...

A construction which i hate with a burning passion. Why on earth does
the append method of a StringBuffer return a StringBuffer? In what sense
does that method evaluate to a StringBuffer? How does that have any
semantic meaning? It's a perversion of the normal rules of method design
to accomodate a particular usage, which is unacceptably awful. The
syntaxes were kicking around are ways of enabling that compact style
without needing to pervert the design of code.

possibly, but it is not that terrible/unusual...
basically, this sort of thing at least allows some vague approximation
of FP coding styles, where not every task is ideally suited to an
OO-based design.


admittedly, I would rather also be able to do some more C-like stuff in
Java as well, but alas...


for my uses, I was actually partly considering (as an extension) the
possibility package-scoped functions (technically, they would likely
exist inside special "hidden" classes), as well as idle thoughts about
handling partial classes (which are possible in my VM core, but lack any
good way to express them either in Java or in the way packages/classes
are managed).

technically, as implemented, "java/lang/String" is implemented using the
same basic mechanism I would use for partial classes, since the class
needs to exist before running the classloader, which is needed to load
String, the result being that a stub version of the class is created (by
the VM), and then the proper class is loaded and forced in on top of it
(basically, the classes merge at this point).


or such...
 
M

Mike Schilling

Lew said:
What do you mean by "structs"?

I'd guess it's a C or C++-like struct: an object all of whose fields are
public. (In C++, that may be a default rather than a uniform rule. I
honestly don’t recall.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top