6 ms·
Scala is awesome–you should definitely learn it. Scala does provide you with enough rope to hang yourself with. What's the solution to this? A. Don't hang your
by nessus42 15y ago
Scala is awesome–you should definitely learn it.
Scala does provide you with enough rope to hang yourself with. What's the solution to this? A. Don't hang yourself. New Scala shops should definitely abide by the style guide that is provided at scala-lang.org to help with this.
Also, use implicits and multiple inheritance very judiciously. One thing that is quite true from the OP, is that the "cake pattern" is indeed "the bakery of doom". If you have to use dependency injection, use something sane, like Guice. Or just ol' constructor injection.
My only big gripe with Scala is that OO syntax is a blight on the world. They should have provided multi-methods instead, so everything could be done with functional syntax.
- eli_gottlieb 15y ago>My only big gripe with Scala is that OO syntax is a blight on the world. They should have provided multi-methods instead, so everything could be done with functional syntax. I actually disagree. Functional syntax means that you need to start using qualified names or polluting your namespace (think of module/import usage in Python, but without OOP dot-notation). I like being able to say: val herp: Option[Derp] = hurr() herp.getOrElse(Darpity) Leaving aside the awful metasyntactic variables, the `getOrElse` method could exist on any number of classes (stuff like `map` sure does!), but I never have to use a qualified name to get the right one. I use dot-notation on the object itself to qualify the method name.
- chc 15y agoDo you find that's a problem with CLOS or Clojure multimethods? Because I never noticed much of what you seem to be talking about.
- eli_gottlieb 15y agoAs I said above, think about a method like map. map :: [a] -> (a -> b) -> [b] Well, actually, any functor has a map method, by definition! So we'd have to write a type-class: class Functor f where fmap :: f a -> (a -> b) -> f b Now how would we represent this as a generic function? method fmap<a,b>(as: Functor<a>,f: a -> b): Functor<b> And then implement specialized methods for each actual functor? override fmap<a,b>(as: List<a>,f: a -> b): List<b> Now everything involving functors performs a dynamic dispatch and might lose type information at its call-site, and we now have to deal with Functor<a> being some kind of superclass, a superclass without data slots of its own just to accommodate our need for this "interface". In Scala, rather than doing that, we would just define Functor[A] as a trait: trait Functor[A] self => { def map[B](f: A => B): self[A] } And now every time I call the map method on a Scala object, it statically dispatches via dot-notation. So my compiler knows that calling map on a List[A] gives me back a List[B], and that calling map on an Option[A] gives me back an Option[B], and I didn't need any implicits to get it done.
- nessus42 15y agoI do not see why your worries cannot be addressed. In fact, IIRC (it's been a while), the programming language Cecil does just that. http://www.cs.washington.edu/research/projects/cecil/www/cecil.html http://www.cs.washington.edu/research/projects/cecil/www/cec...
- eli_gottlieb 15y agoWell, let me take a deeper look at the material. I've based most of my own language work on multimethod systems like those of Cecil, but there's a few things I immediately see on the page: * Cecil divides its type system from its object-inheritance-overriding system. Huh? * Cecil is dynamically typed with static sprinkles on top. So we have dynamic vtables, and also F-bounded polymorphism. * Methods are referred to as being attached to objects, even though they are multimethods. This appears to imply asymmetric multimethods. Again, huh? What a strange design decision to make! * Cecil offers nothing for dealing with ad-hoc polymorphism (ie: operator overloading). Admittedly, when Cecil was published, type-classes didn't even exist yet.
- nessus42 15y agoMethods are referred to as being attached to objects, even though they are multimethods. This appears to imply asymmetric multimethods. Again, huh? What a strange design decision to make! Method dispatching is done symmetrically on the arguments in Cecil.
- eli_gottlieb 15y agoOK, I've read their doc now. And what I can say is, they don't solve the problem I've mentioned at all. Their dot-notation is just syntactic sugar for an "ordinary" multimethod call. It does nothing for module selection. This means you've got to either use qualified module names, make sure never to import two modules that export an identically-named method, or (if the methods have similar signatures) resort to a type-class.
- nessus42 15y agothink of module/import usage in Python, but without OOP dot-notation I don't find that to be a problem. In fact, I love Python's module and import system. And the worst thing about Python is it's OO dot notation. I wish that Python had multi-methods too, and no OO-style method calls.
- pka 15y agoSo instead of writing herp.getOrElse(Darpity) you'd write getOrElse(herp, Darpity) Polymorphism doesn't need to be tied to the first argument's type, it can depend on any number of properties of any number of arguments (see CL's and Clojure's multimethods).
- eli_gottlieb 15y agoI'm not talking about polymorphism at all. I'm just talking about namespacing, name look-up for the method. Think of a world in which any number of classes might have a `getOrElse()` method, and they don't all do the same thing (so they're not just all methods of a single generic function). Now, how does the compiler know which one you're calling? We could use some form of static overload resolution (like type-classes). However, it really does seem (to me) to be easier to just resolve the static overload based on the static type of the first argument, and then throw the rest of the overloading problems at dynamic dispatch. When you think of a class as both a type and a module, it gets clearer. Many classes in the Scala collections library have a `map()` method. We could code `map()` as a single, universal generic function that dynamically dispatches on its first argument type... but nobody ever cared to override map as a virtual method anyway and that doesn't give us a consistent return-type at all. All we really want to say is that calling map over a `[a]` with a function `a -> b` returns a `[b]`.
- nessus42 15y agoSo, what you're saying is that we all of parametric polymorphism, ad hoc polymorphism, and subtype polymorphism, right? You'll get no argument from me, but that doesn't mean that there should be an unfortunate syntactic distinction between the three.
- nessus42 15y agoThe above should read, "So, what you're saying is that we need all of [...]". Sorry about that!
- eli_gottlieb 15y ago