Subject: Re: [scala-user] for-loop vs for-yield loop? Hi Haoyi, Am Dienstag, 21. Februar 2012 22:00:59 UTC+1 schrieb Haoyi Li: > > Roland, > > Thanks for the detailed reply =) It was very useful. Some followups: > > > No, because there is a fundamental difference between context-free and > context-sensitive grammars; count that one as an infinite factor when > comparing simplicity ;-) Also, you would not remove one language feature, > you would only hide it some more and make it more difficult to specify its > semantics. > > Is the Scala grammar context free? Apart from that, are most commonly used > languages context-free? I really don't know. > > Yes, Scalaâs grammar is context free, which is very much intentional. C++ is the best example why this is desirable. > > Also, you would not remove one language feature, you would only hide it > some more and make it more difficult to specify its semantics > > Isn't removing the whole for(...)yield{...} thing removing a language > feature? Sure you could still use map() and foreach() to do the same thing, > but those are just functions and have no special syntax the way > for(...)yield{...} does. > > Maybe I missed something: removing âforâ was not proposed, was it? You just wanted to âinferâ the yield. > > The Scala compiler does not have any means to prove your assumption > (thatâs the halting problem again). map() and foreach() are completely > different methods, they bear no relation whatsoever as mandated by the > interface. That there is usually a connection in concrete implementations > is pure coincidence. > > I accept that if the two for-constructs are syntactic sugar for method > calls, then they should stick to their respective methods. > > Good :-) > I suppose what I am really arguing is that maybe they shouldn't just be > syntactic sugar for method calls, but rather have their own semantics as a > for-loop and a list-comprehension, which follows the way methods work for > consistency, and happens to use the method-calls under the hood for DRY. I > think defining them in terms of "this is how they should behave" -> "figure > out implementation" is better than "this is what implementation they wrap" > and leaving it at that. > > That would be strictly less powerful, though. The way for-comprehensions are specified allows the implementation of very different things using this syntax, it is by no means limited to operations on collections. E.g. monadic operations, composition of Futures, anything you would want to write down as for { a <- b c <- d if x } g(a, c) And that is enabled by decoupling the syntax from context and semantics: this expression will be translated given that b and d support methods with certain signatures, no matter what these do internally. That is a very straight-forward language feature with a broad spectrum of use cases, hence (in my eyes) a good idea. Special-casing collections, requiring syntax-relevant semantic connections between different methods, that sounds like a narrow special feature to me, hence a bad idea. I might of course be wrong, and I have never designed a language myself (and had to live with the result), so take this with a pinch of salt. > > if the syntax allows different transformations based on context, that > is the worst thing you can do to a programmer (or any tool which tries to > work with your code, like IDEs). > > Isn't that the entire basis of abstraction though? That the same-looking > command/statement/expression can do different things depending on context? > That's basically the argument given for why Java does not have operator > overloading, and I don't think it's really valid; I really enjoy being able > to effectively overload operators in Scala/C#/Python, leaving aside the > nitpicking about operator vs. funnily-named-method. > > Thatâs all well in semantics-land, but not in syntax-land. > > Also, the type-inferencer would not âoptimizeâ anything (that is not > its job anyway), because calling a completely different method is not a > valid optimization. > > Isn't "calling a different method" the whole basis function inlining and > dead code removal? > No, you are missing the point that the result of the optimization MUST be equivalent to the original code, i.e. no observable semantic differences (making it faster is not semantics). Hence calling something named âforeachâ instead of âmapâ is not an option. > That rather than calling a method you call his contents directly, or you > don't call it at all? Isn't quite a lot of what optimization in general is > about doing stuff like that, inlining, shifting variables to local scope, > looking at the types (inferred or explicit) of variables and doing clever > semantic-preserving refactorings? > > > Again I know nothing about the internals of the Scala compiler (and not a > huge amount about compilers in general!), so I'm only speaking in very > general terms, but it seems that none of these problems are insurmountable. > To the end-user having two different language constructs that look almost > the same and do two very similar things (as well as two things you almost > never want to do!) but are not interchangeable seems incredibly awkward. > > The user chooses carefully whether or not to produce a resulting value and expresses that using (or omitting) âyieldâ. The user may then also choose to not store a generated value. What I find more awkward is second-guessing what the compiler might infer regarding the necessity of generating that value. Regards, Roland |