Delurking comments on the 0.1.5 specification
Jim Mayer
jim at pentastich.org
Fri Apr 2 22:34:06 PDT 2010
On Fri, Apr 2, 2010 at 11:44 AM, Neal Gafter <neal at gafter.com> wrote:
> On Thu, Apr 1, 2010 at 9:30 PM, Jim Mayer <jim at pentastich.org> wrote:
...
>> Unfortunately, I don't know how to get to a closure mechanism that
>> supports full transparency from Java as it exists today. I don't mean
>> technically, because I think you've demonstrated pretty convincingly
>> that it can be done. I think there are issues of cultural change, of
>> expectations, of business models, and of application spaces.
>
> Isn't it always someone else's fault that we don't try to do what we
> feel is the right thing?
I really wasn't attempting to assign "fault" for anything, and if my
comment came across that way it was unintentional. The cultural
change issues are unavoidable, and the expectation, business model,
and application space issues are all based on legitimate concerns.
They're not necessarily my concerns, but I know and respect people who
have them. The concerns mostly have to do with risk management,
training, and performance/footprint and, perhaps unfairly, I'm not
going to try to enumerate them.
>> In the
>> end, the best bet may be to try to make sure that nothing gets added
>> to the byte codes or JVM that would make a language that DID support
>> all of this impossible or horribly inefficient.
>
> And, we can make sure nothing gets added to Java that makes it
> difficult to support transparency in Java in the future.
I would like to see that. I would also like to make sure that we
don't short-change what we can do now. I would be very happy if we
can pull off both.
>
>> <geek-mode>
>>
>> If "E" is a Java expression (not statement), then, assuming that we
>> changed the way the proposal handle's 'this', aren't the following all
>> equivalent?
>>
>> E
>> #(){return E;}
>> #(){return #(){return E;};}
>>
>> I think this follows from the fact that expressions can't contain
>> 'break', 'continue', or 'return' except insofar as they show up in a
>> lambda expression (which acts like a function body).
>>
>> </geek-mode>
>
> Yes, they are equivalent (presuming you meant to invoke the resulting
> lambda at each step).
My bad...
> However, that's not transparency. Transparency
> is a property of the language, not a property of particular programs.
Agreed.
> If your question was about the possibility of defining the lambda
> syntax so that the return and semicolon surrounding the result
> expression are part of the lambda syntax and not a statement,
Nope... I didn't mean that at all. I was observing that, if we
limited ourselves to expressions (because they currently don't contain
'break', 'continue', or 'return') then we still have the substitution
property, at least if we avoid having 'this' refer to the lambda
expression object (whatever that is).
One concern I do have is that if we have an invocation syntax that
looks like a method definition, then I think we will create a lot of
confusion for people who expect that break and continue will be
illegal and that return will exit from the "lambda expression that
looks like a method definition". I wonder if a lot of the "it doesn't
look like Java" comments come from a similar place.
Has anyone involved with BGCA (or similar) efforts come up with ideas
that would help bridge that sort of "point of view" gap?
For example (and this is NOT a proposal), I could imagine:
// A lambda expression that acts like a method with respect
// to break, continue, return, etc. It looks like a method
// definition, so nobody will be surprised.
function(int x) {
return x + 1;
}
// A "block" that is compatible with transparency.
// It looks, well, at least different from a method
// definition, so people will accept that it means
// something different as well.
[[ int x : x + 1 ]]
Then we could say things like:
withLock(myLock, [[: doSomething() ]])
and
map(function(int x){ if (x < 0) return -x; else return x; },
someCollection);
Maybe the "block" form could replace the expression form in the draft
specification. I don't think this is a PL/I like "do everything"
suggestion... You don't have to go farther than the archives on
lambda-dev to realize that reasonable people are looking at the
problem in very, very different ways.
If Java was a new language, then something like this would just be
nasty extra syntax. Given Java's rich history, maybe we should
consider making "new" semantics visually distinct.
>>> In the factorial example
>>>
>>> #(int n)(n == 0? 1 : n * #this(n-1))
>>>
>> It seems that something like the logic used to determine the type of a
>> conditional expression ought to be applicable.
>
> What is the type of the third operand of the conditional operator? Is
> it long (because the type of the lambda' result is long)? Is it
> double (because the type of the lambda's result is double)? Or
> perhaps it is int?
Well, I was thinking that it was undefined, and that we'd apply a rule
stating that the result type of the conditional E1? E2 : E3 was
defined as the type of E2 if the type of E3 was undefined (and visa
versa). At this point, you'll probably smile and point out that
long factorial(int n) { return n == 0? 1 : n * factorial(n-1); }
is perfectly legal (if unfortunate), and that therefore
#long(int n) factorial = #(int n)(n == 0? 1 : SELF_INVOCATION(n - 1));
ought to be legal as well. How sad for both of us :-)
I suppose the real problem is going to lie with implicit conversions
and method overloading.
int x = #(int n)(n == 0? 1 : SELF_INVOCATION(n - 1))(5);
long y = #(int n)(n == 0? 1 : SELF_INVOCATION(n - 1))(5);
double z = #(int n)(n == 0? 1 : SELF_INVOCATION(n - 1))(5);
// void foo(int v) is defined
// void foo(long v) is defined
// void foo(Integer v) is defined
// go wild...
foo(#(int n)(n == 0? 1 : SELF_INVOCATION(n - 1))(5))
// void bar(int v) is defined.
// void bar(String v) is defined
bar(#(int n)(n == 0? 1 : SELF_INVOCATION(n - 1))(5))
And, just for fun:
System.out.println(#(int n)(n == 0? 1 : SELF_INVOCATION(n - 1))(5));
I was thinking that if R1, R2, ..., Rk were the legal result types
then we could look at the set of types Tj (a subset of {Rk}) such that
Tj "worked" and that the expression would be legal if and only if that
set had exactly one member. By that standard the assignments would
all be legal (with the type bound to int, long, and double), the "foo"
method calls would not be legal, the "bar" method call would be legal
(with the type bound to int), and the println would not be legal.
Since the last paragraph made me think of type resolution in Ada I
formally give up on the idea.
-- Jim
More information about the lambda-dev
mailing list