Re: [scala-language] The cake’s problem, dotty des ign and the approach to modularity.
Shelby <[email protected]>
| Newsgroups | gmane.comp.lang.scala |
|---|---|
| Message-ID | <[email protected]> |
In my previous messages, I expressed an idea for injecting the draw interface(s) to the function for the type(s) in the collection(s) input to the function. I also suggested the compiler could do this automatically, for example the function: def f(a: List[Drawable]) ... I proposed that example function could be invoked by a caller possessing any List[T] where T could be an intersection of types which implement the Drawable interface, and the compiler would automatically compile to a function that supports manual injection as follows and automatically implement the boilerplate (both within the function and at the call site) to make it seamless. def f(a: List[T])(implicit b: Drawable[T]) ... Note the implementation of Drawable[T] is a object and not a supertype of T, i.e. a typeclass. Afaics this solves the Expression Problem in that any new interface can be added for any pre-existing type T without touching nor recompiling the source code for T or any existing functions that consume existing interfaces implemented for T. Any reaction or thoughts on this idea? The only problem I thought of so far is that due to type erasure when compiled to virtual machines (VMs) that erase types such as Java's, the call site may not know the actually type of T in a collection and thus be unable to construct the match-case boiler plate to apply the correct Drawable[T] object implementation for each type in the intersection of types in T. Type erasure can be worked around with implicit manifests so this isn't a show stopper afaics. Virtual inheritance appears to me to be an anti-pattern. It breaks semantics quite easily. For example the common example that a square virtually inherits from a rectangle. Then square has the semantics that you can't set the width and height independently, thus the invariants of the semantics of setWidth or setHeight virtual methods is broken. As I wrote previously, it seems we still need subtyping for parameterized types (what I referred to as a container, e.g. List[T]) because otherwise we can't add new types to the intersection of types in T at runtime (i.e. T would need to be invariant). Note when I am referring to T of List[T] being an intersection of types, I mean for the new DOT (Dotty) calculus. We all know the existing Scala subsumes the types (usually to Any) that are added to parameterized types such as List[T]. Thus it seems to me DOT (Dotty) is the correct direction to go and we need to decide what else we should throw away from the existing Scala features. I mean I would like to see a base of features for something that is not Scale (i.e. is Dotty) and then you can build the compatibility features for the legacy Scala orthogonal to the base so we can keep the base mean, clean, and awesome. I may be interested to fund this if we can some clear understanding. I am not expert enough to know if what I am proposing is even correct. Apologies for being so audacious. I am rushed and just trying to be a high level (generalist) thinker here. You all are down in trenches with this and can better access. i have the capacity to learn and understand if I drill down but not the time to do so because I am spread out on many big projects (currently in the Bitcoin space mostly which is where the potential funding might come from). On Wednesday, June 17, 2015 at 1:29:24 AM UTC+8, Rex Kerr wrote: > > > On Tue, Jun 16, 2015 at 12:53 AM, Shelby <[email protected] > <javascript:>> wrote: > >> >> Am I homing in on the generative essence? Nobody has been able to >> succinctly and concretely explain to me why I need Scala and not Haskell >> disregarding the Java compatibility or lazy by default differences. >> >> > This is kind of off-topic for the original thread, but: > > Inheritance provides a way to automatically assemble chains of > mutually-dependent functionality without having to worry about the > details. It's a somewhat fragile solution, but nothing other than > extremely late binding via (something computationally equivalent to) vtable > lookup really does the trick. > > So if you have, for example, a bunch of drawable windowing components with > all sorts of elaboration therein, you can still have a xs: List[Component] > and get something sensible with xs.sortBy(_.zDepth).foreach(draw). > > It's not the only way to solve the problem at all, since any problem you > can solve with inheritance you can also solve with composition, but with OO > it's really easy to make most everything overridable so you have to go back > and modify your library less often. (Unfortunately, due to a lack of a > really robust way to specify logical dependencies, you often need the > source code to the library anyway so you know what is safe to override > alone, what must be overridden in pairs, etc.). > > It also doesn't play terribly nicely with immutability because you lose > track of which constructor you ought to use. The whole _point_ of OO is to > lose track so you don't have to worry about it, but then when you need to > worry...well...you're stuck. A classic example is > > List(new A, new A{ override def foo = "different" }).map(x.asCapitalA) > > If `asCapitalA` has mutating side-effects, you retain the distinct `foo` > behavior. If, in contrast, it creates a new immutable A, your unique `foo` > behavior is lost. > > So you might just reject OO as a tool that helps you most in a situation > that you avoid anyway. But that doesn't mean that there are equivalently > easy functional or monadic or other ways to do the same thing. Everything > else is harder. > > --Rex > > -- You received this message because you are subscribed to the Google Groups "scala-language" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.