The Artima Developer Community
Sponsored Link

Weblogs Forum
Inner Classes or Closures

38 replies on 3 pages. Most recent reply: Apr 16, 2007 5:34 PM by Howard Lovatt

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 38 replies on 3 pages [ « | 1 2 3 | » ]
Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Inner Classes or Closures Posted: Oct 17, 2006 5:04 PM
Reply to this message Reply
Advertisement
Carson,

> Why on earth should it? It's just a '\' character. Sun
> owns the parser. They can do whatever they like. The
> rule I would adopt is: an expression closure body can
> stand alone without any additional syntax. A statment
> list closure must be enclosed in {}'s. Simple, easy to
> parse, and it makes the common case beautiful. The BNF
> is easy enough:
>
> closure_expr -> \ args -> closure_body
> closure_body -> expr | '{' statement_list '}'

The problem is that:
    each list, \elt -> sum += elt; ;

Has two expressions in it and hence needs the two semicolons; one expression is the whole thing, the second is the lamda expression. You can't arbitrarily change the parser, not because you don't own it but because it must be able to parse old and new code, and I think this is one of the cases where you can't change. Consider the following that shows only one semicolon:
    method \x -> Type local = new Type( x ), argumentOrLocal;

What is this, it could be a method with two arguments, the first a lamda expression. But it could also be a method with one argument and a lamda expression that declares two variables. The example should be:
for two arguments
    method \x -> Type local = new Type( x );, argument2;
or for two locals
    method \x -> SomeType local = new Type( x ), local2;;

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Howabout functions as first class objects? Posted: Oct 17, 2006 5:36 PM
Reply to this message Reply
Todd,

> >Closure | First Class Function == Poor Man's Inner Class
>
> So you prefer more complexity in your language? Because
> that's what you are advocating.

See below

> Smalltalk blocks are just chunks of code - similar to
> CompiledMethods - which are also implemented as objects.
> Once you dig into it you find that the system is built
> t out of one thing. Systems like that are exceptionally
> powerful and profound.
>
> Versus the dozen or so things with different semantics you
> find in Java. Which means the language is much more
> complicated to grasp, it has many more rules, yet it is
> still less expressive. In general - more things impiles
> less power.

I agree with the point that the less things you have the better, but ...

> Inner classes are definitly a poor man's closures.
> Because they are special cases and special cases are
> e weaknesses.

Why are they a special case? Why can't you declare the method which resides inside a class as the natural building block? It is an OO language after all :) and a class with a collection of methods, annotations, and fields is more powerful than a block. If you view the method as the building block then you view the blocks associated with for, if, etc. as the odd ones out that like primitive types wouldn't be in Java in the ideal world. Consider:
    for ( Findable item : findables ) {
      if ( item.isFound() ) {
        break;
      }
    }

Is odd code, there are two blocks and the break breaks out of all the blocks up to and including the first loop block. Therefore we don't have one block type but many. In Java there is a least four block types: scoping blocks, method blocks, if blocks, and loop blocks and break, continue, and return behave differently depending on which block type they are in and which type of block the block they are in in enclosed in (few!). Hardly simple stuff.

Wouldn't life be simpler if you had only one block type, the method block. The above example, using SSCO syntax, might be:
    forEach findables new.{ (item)
      ifTrue item.isFound new.{
        endEach = true
      }
    }

Assuming methods forEach and ifTrue where appropriately defined.

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

Re: Howabout functions as first class objects? Posted: Oct 17, 2006 6:15 PM
Reply to this message Reply
> Why are they a special case? Why can't you declare the
> method which resides inside a class as the natural
> building block? It is an OO language after all :) and a
> class with a collection of methods, annotations, and
> fields is more powerful than a block.

It is not. It is more complicated than a block. However, in Smalltalk, I can extend BlockClosure and make new kinds of things, with different scoping rules.

This argument is made much better elsewhere than I can fit here:
http://www.whysmalltalk.com/articles/panici/smalloojava.htm

As to whether Java is an OO language - this is only true for sufficiently constrained values of Object.

Java
1) Has primitives that are not objects
2) Has arrays that are not objects
3) Has something called a Class that is more like a class description and is not an object (although I concede it looks a bit like one)
4) Has no actual class objects or class methods and an odd sort of method hiding behavior on the class side as you move/down up the hierarchy.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Howabout functions as first class objects? Posted: Oct 17, 2006 6:43 PM
Reply to this message Reply
Todd,

In Smalltalk you can make an anonymous instance of a BlockClosure class with some spiffy syntax, in Java you can make an anonymous instance of any non-final class or any interface and the syntax isn't so spiffy. What the proposals are all about is adding some spiffy syntax to Java so that making instances of anonymous inner classes is easier.

I don't see the relevence of the "you can rewrite the compiler" argument in the Smalltalk article. You can rewrite the compiler for Java if you want - so what!

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

Re: Howabout functions as first class objects? Posted: Oct 17, 2006 8:20 PM
Reply to this message Reply
Completely missed the point

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: Inner Classes or Closures Posted: Oct 18, 2006 2:11 AM
Reply to this message Reply
> The problem is that:
>
>     each list, \elt -> sum += elt; ;
> 

> Has two expressions in it and hence needs the two
> semicolons; one expression is the whole thing, the second
> is the lamda expression. You can't arbitrarily change the
> parser, not because you don't own it but because it must
> be able to parse old and new code, and I think this
> is one of the cases where you can't change. Consider the
> following that shows only one semicolon:
>
> method \x -> Type local = new Type( x ),
> x ), argumentOrLocal;
> 

> What is this, it could be a method with two arguments, the
> first a lamda expression. But it could also be a method
> with one argument and a lamda expression that declares two
> variables. The example should be:
>
> for two arguments
>     method \x -> Type local = new Type( x );, argument2;
> or for two locals
>     method \x -> SomeType local = new Type( x ), local2;;
> 


I grow frustrated by this thread.

As I said previously, there are two very simple cases: either the closure body is a simple expression, in which case no enclosing syntax is needed, or it is a statement list, in which case you must wrap it in {}'s to delimit the body. Please, for the love of our Savior, no double semicolons. They are stark, raving, utter syntactic lunacy.

I really have no idea what imagined parsing problem you are talking about in the code above, but let me attempt a response:

  method(\x-> Type local = new Type(x), argument2); //two args, simple as pie.  
  //Look!  A comma separates arguments!  And, as luck would have it, that
  //is exactly how the java parser already works!  No work!
 
  method(\x -> { Type local = new Type(x), local2 } ) // one single closure arg
  //Hey, look at that.  Multi-expression/statement closure bodies are enclosed
  // in curlies, just like good old method bodies.  It's almost... consistent!
 

This is simple parsing stuff. We *have* the technology.

_shrug_ I'm just a simple cave man.

Cheers,
Carson

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: Inner Classes or Closures Posted: Oct 18, 2006 2:16 AM
Reply to this message Reply
Make the second example:

  method( \x -> { Type local = new Type(x); local2 }  )


Statement lists internally are, of course, separated by semicolons, not commas. What a happy set of parsing circumstance...

Cheers,
Carson

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Inner Classes or Closures Posted: Oct 18, 2006 2:25 AM
Reply to this message Reply
At first glange all these 'solutions' are unreadable and ugly. Too ugly to incline me to investigate them and sufficiently ugly to make me investigate Python and Ruby (maybe even Smalltalk, they're that ugly).

The heavy reliance on the correct use use of differently shaped brackets, colon and semi-colons is steadily reducing Java's scope from being a language for use by general programmers to a notation decipherable only by geeks. One solution above even appears to advocate the absence of a semi-colon as an indicator!

One thing that is missing from all the above is 'control' code. Where is the equivalent Java 1.5 that the new notations would improve?

As things stand, I can't evaluate the solutions because I simply can't read them. Of course that may be me just being thick but as far as I'm concerned "Unreadable code is unusable code.".

Vince.

"Can you instance a type of that class?"
Charles Dickens - Bleak House - 1853

Mark Thornton

Posts: 275
Nickname: mthornton
Registered: Oct, 2005

Re: Inner Classes or Closures Posted: Oct 18, 2006 3:25 AM
Reply to this message Reply
> One thing that is missing from all the above is 'control'
> code. Where is the equivalent Java 1.5 that the new
> notations would improve?
I think that was the even more ugly bit listed first (labelled Java Injection, etc). Maybe you are still suffering from generics indigestion!

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Inner Classes or Closures Posted: Oct 18, 2006 4:22 AM
Reply to this message Reply
> I think that was the even more ugly bit listed first
> (labelled Java Injection, etc).

doh!

> Maybe you are still suffering from generics indigestion!

Very true.

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: Inner Classes or Closures Posted: Oct 18, 2006 10:09 AM
Reply to this message Reply
> At first glange all these 'solutions' are unreadable and
> ugly. Too ugly to incline me to investigate them and
> sufficiently ugly to make me investigate Python and Ruby
> (maybe even Smalltalk, they're that ugly).

_shrug_ I think


closure -> '\' arg_list '->' closure_body
closure_body -> expr | '{' statement_list '}'


is pretty clean and minimal, calling out the new concept clearly, but retaining a moderately familiar syntax. Admittedly, the '\' character standing in for a lambda is pretty weenieish, but I'll take it over ruby's

{|arg_list| body}

syntax. (Don't get me wrong. I *love* ruby, except for the lack of static typing.)

If radical syntax bothers you, Smalltalk is even further out there, IMO. As I understand it (and I haven't written a line of python in the five years since I found ruby) Guido actually removed the hacked-up anonymous closures that python supported, in favor of list comprehensions.

> The heavy reliance on the correct use use of differently
> shaped brackets, colon and semi-colons is steadily
> reducing Java's scope from being a language for use by
> general programmers to a notation decipherable only by
> geeks. One solution above even appears to advocate the
> absence of a semi-colon as an indicator!

Yup. Which is why my proposal does away with nearly all of it.

> One thing that is missing from all the above is 'control'
> code. Where is the equivalent Java 1.5 that the new
> notations would improve?

I have no idea what that means.

> As things stand, I can't evaluate the solutions because I
> simply can't read them. Of course that may be me just
> being thick but as far as I'm concerned "Unreadable code
> is unusable code.".

It's not you being thick. Closures are a strange concept at first anyway, and the vast majority of the proposals are so impossible to parse mentally that they near-fatally obscure the idea. We should strive (as in ruby) to get the syntax out of the way.
  employee_names = employees.map{| employee | employee.name } //ruby
  employee_names = employees.map(\ employee -> employee.getName() ) //what we *should* be able to do in java

Cheers,
Carson

Morgan Conrad

Posts: 307
Nickname: miata71
Registered: Mar, 2006

Re: Inner Classes or Closures Posted: Oct 18, 2006 11:46 AM
Reply to this message Reply
I think I'm with Vincent. Confused, ugly syntax.

For the example with math on numbers in a list, I do that a lot. I have an algorithm where sometimes you subtract to normalize a result to a control, and sometimes you divide.


List results = new ArrayList();
double controlValue = comesFromSomeCalculation();
for (Number n : theCollection)
results.add(normalizeToControl(n.doubleValue(), controlValue ));


where normalizeToControl is an abstract method that subclasses implement with difference or divide. The code is real clear IMO. If normalizeToControl eventually needs to do FFT fuzzy logic neural network math, a sublcass can do it. (Or it could be DIPped if one prefers DIP to subclassing)

NOTE - I'm cheating a bit here, it would be really nice if Number were an interface.


As for Carson's comment

employee_names = employees.map(\ employee -> employee.getName() ) //what we *should* be able to do in java

I'm confused. If there is actually a Map, which presumably maps names to Employees,

map.KeySet() is what you need.

If there is a list of employees, if it were important to the be able to get a list of their names, I'd write a helper method that takes a list of Employess and returns a list of their names. That way, the code exists in ONE place. So that when a requirement comes down to support sorted Chinese names with last names first you know exactly where to look. Not in little tiny cute closures scatterred all over the place that can't be subclassed or easily modified.

If it's not important to get a list of their names, the code is probably only in one little method and who cares how many characters you type?

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: Inner Classes or Closures Posted: Oct 18, 2006 5:38 PM
Reply to this message Reply
_throws up hands_

"map" is a method my man. You really need to give ruby (or lisp, or smalltalk, or any language with decent closure support) a serious try. It will change your life.

Unfortunately, you will probably also start hating java. _shrug_ Tradeoffs...

Cheers,
Carson

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Inner Classes or Closures Posted: Oct 18, 2006 6:30 PM
Reply to this message Reply
The exact syntax seems to be a real big issue; to me so long as it is clear and concise it doesn't really matter what it is exactly. Below are some of the examples from this forum, as you can see they are very similar - do people really have a strong preference for one over the other?
    employeeNames = to employees new.{( employee ) employee.name } // As proposed in this blog 
    employeeNames = to employees { employee => employee.name } // Scala like
    employeeNames = to employees {| employee | employee.name } // Ruby like
    employeeNames = to employees {\ employee -> employee.name } // Haskel like
In all cases 'to', using standard Java, would be something like:
    public static < R, A > List< R > to( final Iterable< A > collection, final Function1< R, A > cast ) {
      final List< R > result = new ArrayList< R >();
      for ( final A item : collection ) result.add( cast.call( item ) );
      return result;
    }

Note: In the above code I chose the name 'to' for the function rather than 'map' because 'map' already has a strong connotation in Java and is therefore confusing to use the same name for something else. The name 'to' is meant to conjure up something like 'toString' or a cast. It casts (converts) each element of the input collection into a new list.

The last three of the above cases are very similar, really just minor syntax variations on each other. The first one has a slightly changed syntax in that the keyword new is retained to remind you that a new object is created (the closure). Is the clarity that the keyword new brings worth the extra four keystrokes?

PS To Carson re. static method: I have used a static method rather than a member because I think it unlikely that anyone will want to change the collection classes; but if you want to write your own collection classes that expand on the standard ones and add methods as members then you can easily do it.

PPS To Carson re. why braces used: A comma is used to separate variable declarations in the same statement as well as argument lists, hence you need something to delimit the end of the closure other than a comma. In the above I have used braces.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Inner Classes or Closures Posted: Oct 18, 2006 6:44 PM
Reply to this message Reply
Morgan,

Using the 'to' method defined in the post above, adding in the generic types, and using the syntax I suggested in this blog, your example might be:
    double controlValue = comesFromSomeCalculation;
    List< Number > results = to theCollection new.{( n ) normalizeToControl n.doubleValue, controlValue };

Which is a bit shorter and some people would argue clearer (personally I am not sure that it is any clearer). The question is, is it worth adding spiffy new syntax for the gains you get? What do you think?

Flat View: This topic has 38 replies on 3 pages [ « | 1  2  3 | » ]
Topic: Inner Classes or Closures Previous Topic   Next Topic Topic: A First Look at Apollo

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use