4 ms·
What you say is correct, but I think your mental model isn't the mental model many people work with. One possible way of thinking of things is "methods" and "f
by lihaoyi 9y ago
What you say is correct, but I think your mental model isn't the mental model many people work with.
One possible way of thinking of things is "methods" and "function values", where you need to eta-expand something to go from "method" to "function value". This is something people get used to when working in Scala for a while.
Another way of thinking of things is "things you can call" and "things you cannot call". In this case, it does not make sense to care about "method" or "function value": if it's callable, it should remain callable in the same way as I pass it around, until I call it. If you come from a Python, or JS, or other background, this is the mental model you will have.
I personally think the second mental model makes much more sense, and the first is a weird artifact of programming in Scala that you don't see much elsewhere (though I admit C# has a similar dichotomy)
I don't find the "people may forget to leave off parentheses" a convincing argument. People may forget to call `.flatten` on nested lists too; doesn't mean we should go flatten everyone's lists for them automatically. Furthermore, if you as an individual wanted to flatten `() => T` into `T` automatically,
you can easily do that within your own project with an implicit conversion:
implicit def flatten[T](f: () => T): T = f()
The same way you could use an implicit to automatically `flatten` nested `List`s, or automatically call `.get` on `Option`s. Both of those are similar to automatically calling functions to avoid "confusion", and something I think most people in the community will agree would be a terrible thing to do
- deleted 9y ago[deleted]
- tekacs 9y agoHm, so I wrote Python for a decade before Scala (and I still write TypeScript & JS) and I'm deeply sympathetic to the 'passing around a callable' way of looking at things. That said, I find Scala's syntax more consistent. I would regularly run into that 'wart' in Python, where changing something between a property and a method would completely change the downstream behaviour (property -> method makes downstream 'calls' eta-expand and method -> property makes downstream calls error, or call the eta-expanded function if the property happens to return a function, both of which are terrible IMO). I guess more than caring either way about number-of-argument-lists, I just disagree (as does a sibling commenter) with automatic eta-expansion, because I think that 'people may forget to call `someFn _`' is unconvincing. If you currently try to pass `someFn` bare, to something expecting a function, you get a very clear error (and in some cases you can actually do this and it's automatically handled, like in `.map(someFn)`). On the other hand, I would find it deeply objectionable if the compiler started magically switching the type of an expression of mine based on the upstream's number of parens. If they change `def foo()` to `def foo` I don't expect the type of my `val x = foo` to change from `() => Int` to `Int` or vice versa.