Re: what is the initial value of arrays of object
Peter Duniho wrote:
For controls, it's possible that the specific variations for each
control will be handled elsewhere (for example, you want a bunch of
buttons that are the same except for their text, which will be set
later). And for sockets, generally the binding that makes each instance
unique happens after initialization.
Thread pools.
Another example that comes to mind is related to Java's lack of
pass-by-reference.
What? Java has little EXCEPT pass-by-reference. Or do you mean for
primitive types? So, for instance arrays of mutable int-holders, which
(unlike int[] cells) would have individual references?
I can certainly imagine a method that requires an
initialized array of mutable objects to be passed to it, for the purpose
of allowing it to return values in those objects. Sure, one could
alternatively have the called method instantiate the objects, but
there's nothing mandatory about that.
And there may be design reasons not to do that -- such as to decouple
the method implementation from the code that decides what exact class of
objects to instantiate.
Heck, even your own post included an example like that, so I'm a bit
confused as your apparent claim that you can't think of examples like that.
That's not to say this sort of thing comes up often enough to justify
building a language feature around the scenario.
Keep in mind that the language feature would be "cheap" in several
senses: not breaking backwards source-compatibility, not really
complicating things too much, and not requiring much actual
implementation effort (in the simplest case, the existing compiler just
has a preprocessing stage prepended that basically does a form of
macro-expansion, with temporaries where necessary to prevent repetition
of expression side-effects of course).
But I think it should
be possible for anyone to recognize that it's at least hypothetically
possible to have code that could take advantage of that.
More than hypothetically. I don't know about you guys but I've
personally seen (and written) real, live, production code that could
have taken advantage of that, had it been available.
Your previous post mentioned a number of work-arounds, but that's surely
not the point. In Java, you can implement whatever functionality you
need.
I should certainly hope so. Ordinarily, one wants languages to be
Turing-complete, unless it's very special-purpose. Even some document
description languages seem to be Turing-complete.
The question is how simple it is to do so, and in thinking about
what features might be useful, being able to do something in an
alternative way isn't necessarily relevant to the question. After all,
there are a number of things in Java that are redundant with other Java
features, but which provide some recognizable benefit in elegance, speed
of development, etc.
Exactly. The relatively recently introduced collection-iterating "for"
loop is a good example. Even the + operator overload for strings, which
was there from the outset, more-or-less.
A few others I've thought might be nice include:
for (type x : coll) {
...
remove(x)
...
}
interpretation changed so that IF there is no method call resolution for
"remove(x)" it invokes the remove on the iterator that exists under the
hood. (Only applied if the argument expression is simply the reference
name for a loop variable that's in scope, not hidden, and from a new-for
loop rather than some other sort of loop.)
for (type1 x, type2 y : coll1, coll2) -- tandem iterations,
generalizable to three or more tandem iterations and stopping when the
smallest collection is exhausted.
typedefs with an optional boolean expressions that is a range
check/validator, and which create immutable value types:
typedef twoDigitInt = int {
this >= 0 && this <= 99;
}
typedef nonEmptyString = String {
this != null && this.length() > 0;
}
This one requires a new keyword, which impacts source compatibility.
Immutability of a reference-type base would be enforced: if any method
invoked on one of these tried to change a non-transient field, a runtime
exception would result, and the compiler would not accept code that
assigned a reference of the base type to a reference of the new type if
that reference was not the direct result of a new expression AND the
base type has non-transient non-final fields. This keeps mutable
references to the same object from being used to violate the range
constraint later. Range constraint tests would be evaluated once at
assignment time (with any side effects occurring then, the once) and a
false evaluation would result in an IllegalArgumentException or similarly.
public class Foo implements BarAlike {
Bar internal = ...;
delegate (internal) method1, method2, method3
}
Shorthand for Type1 method1 (args...) throws Ex1 {
internal.method1(args...); } and so forth. Would need a new keyword
"delegate" and would save a lot of boilerplate typing when implementing
some things using a delegate, or doing some other delegation based
patterns. One issue here is that "delegate" is a not-uncommon variable
name so the source compatibility issue is significant. Perhaps "punt",
which implies the same meaning and is a very rare variable name, instead?
synchronized { ... } as a shorthand for synchronized (this) { ... }
(with "this" being the class object if in a static context)
synchronized (foo, bar, baz) { ... } to synchronize on multiple
resources, with the locks acquired in order of the objects' physical
memory addresses (which the JVM knows, so this is possible, though not
without making a new JVM opcode perhaps). This acquires particular pairs
of locks always in the same order and helps prevent deadlocks, as well
as making conciser code in some cases. Doing the fixed-order thing
without such a language feature is possible, but difficult: the
resources need GUIDs of some sort assigned, that implement Comparable,
and you need an extended sort of Visitor pattern. Your resources need to
extend some class that has a private int guid field and a
receive(Visitor, List<Resource>) sort of method, with the latter being
something recursive like
synchronized (this) {
next = findMinBiggerID(list);
if (next == null)
visitor.visit(list);
else
next.receive(visitor, list);
}
so that the locks are acquired in ascending order of id and then
visitor.visit(list_of_resources) occurs.
What a pain...
The multi-synchronizer syntax added to the language would save some
projects one interface, one abstract class, several short but tricky
chunks of code that might harbor bugs, and method calls, comparisons,
container construction, stack frames, and suchlike per usage. The
performance difference if in a frequently used piece of code might be
considerable, even given the need for an under-the-hood temporary list
of references and sorting operation on same.
Rather, the real question is whether it would be useful, and whether it
would come up often enough to justify the feature. And sure, perhaps
it's infrequent. But it seems obvious to me that the scenarios do exist.
There's also the question of how high a burden of justification should
be needed. Depending on how much work would be involved, or how little,
and how easily backward compatibility could be maintained, the bar might
be higher or lower in each separate case.
Of all the things proposed in this thread so far, the multi-synchronize
is the only really complex one to implement and the only one that might
require changing the class file format, and even then could retain
source compatibility and probably binary compatibility. It's also the
one that is sometimes particularly hard to work around the lack of.
The ones involving new keywords break backwards source compatibility
mildly, can be done without breaking binary compatibility (typedef types
could exist as distinct types only at compile time, and delegates just
expand macro-like into the boilerplate they saved you typing), and are
also particularly useful-looking. Adding "remove" to new-for loops
doesn't actually make "remove" a keyword if done as described above.
Syntax-highlighting editors could color a "remove" they determine to act
as an iterator-remove specially, or as if it were a keyword, per the
developer's choice.
Anyone want any more examples or language-tweaking suggestions? :-)