Return expressions in functions


#1

According to the spec 6.20,

A return expression return e must occur inside the body of some enclosing named method or function. The innermost enclosing named method or function in a source program, f, must have an explicitly declared result type, and the type of e must conform to it.

given the following potential programs, I expect 1 to meet the specced definition:

val f: () => Int = () => return 7

val g: () => Int = return () => 7

we have named functions, f and g, so

A return expression return e must occur inside the body of some enclosing named method or function

is satisfied

The innermost enclosing named method or function in a source program, f, must have an explicitly declared result type

is also satisfied

and the type of e must conform to it.

seems to be satisfied for at least one of those - In my reading for for f, though I could be convinced it’s for g instead.

However, both fail to compile with return outside method definition.

Is this a bug in the spec, the implementation, or my interpretation?


#2

Possibly related: https://github.com/scala/bug/issues/10820


#3

I think explicit return always tries to return from the enclosing method, so I would say the spec is not in sync with reality.


#4

A method is declared with def. The val declarations are making members that store references to functions, not methods. Remember that when you use => you are making a subtype of Function_X_ for X matching the number of arguments.

If you think of this in terms of Java, the lambda syntax is just a syntax for an anonymous class and you implementation overrides some method in the supertype.


#5

The spec says

A return expression return e must occur inside the body of some enclosing named method or function.

(emphasis mine)

I don’t know Java very well, so I don’t know what the analogous concept in Java would be.


#6

Good point. I’m not certain what the term “named function” even means in Scala. A lambda is really an anonymous function, even if you assign it to be stored in a variable.


#7

Some extra discussion on the topic: https://stackoverflow.com/questions/49777021/what-is-a-named-function-in-scala


#8

I submitted a PR to try to clarify


#9

Lambdas in Java are not exactly anonymous class. There’s no class bytecode file for a lambda the way there is for an anonymous class. They rely instead on the invokedynamic byte code instruction that was added in Java 7. I used to think they were equivalent to anonymous classes until I ran into problems with serialization (http://www.cs.unh.edu/~charpov/programming-serial-lambda.html).


#10

Are you sure that you have the right link there? The term “invokedynamic” doesn’t appear anywhere on that page. Indeed, “invoke” doesn’t appear on the page.

However, you are correct in terms of the Java compiler. Here’s a complete discussion: https://www.logicbig.com/tutorials/core-java-tutorial/java-8-enhancements/java-lambda-functional-aspect.html. Note that the runtime has options for what to produce when it hits the invoke dynamic. It can do what is fastest. I have a feeling that there are times when making an anonymous class could be deemed the fastest option if it is going to be used a lot.


#11

Interesting link. Mine was just a side note on serialization, not on invokedynamic.


#12

The thing is that serialization can, and often should, be overridden. So what is serialized doesn’t always reflect the true nature of what is being saved. For example, if you serialize most linked lists, the saved form isn’t going to have nodes. I was wondering if that might be what was happening in your test. Clearly it isn’t. You are seeing the true form in that serialization.