Re: [scala-language] The cake’s problem, dotty des ign and the approach to modularity.
Jon Pretty <[email protected]>
| Newsgroups | gmane.comp.lang.scala |
|---|---|
| Message-ID | <CAE45xci5XDWxCTSODCsB5fbsgSx4Y6V663_VPdgtyjG1bP9Chg@mail.gmail.com> |
This adds little over what Martin said, but for me, the general problem with the Cake Pattern is the other side of the same coin that makes it so convenient: that it is very easy to introduce new dependencies. It's very convenient when constructing a cake that you don't have to define interfaces before you use them, and still have soundness enforced at compile time. But this does nothing to promote well-designed or clean interfaces, and consequently they don't arise naturally. Should you ever have to untangle a cake during a refactoring, you will probably find it unpleasantly difficult. Oliver: The Cake Pattern is a nebulous concept. (You've probably discovered at least that much...) Have you read this paper? It predates the name "Cake" but describes the pattern's usage in the compiler: http://lampwww.epfl.ch/~odersky/papers/ScalableComponent.pdf In addition to Martin's description, I envisaged the trait "slices" of the cake potentially having inner traits which can themselves be combined in parallel with the mixin of the outer traits. These were intended to be "layers", though they're not really an essential part of the pattern. Cheers, Jon On 12 May 2015 at 15:47, Eugene Burmako <[email protected]> wrote: > Well, TreeApi is still part of the cake, because some parameters / return > types of its methods are cake-dependent. > > On 12 May 2015 at 16:44, Oliver Ruebenacker <[email protected]> wrote: > >> >> Hello, >> >> On Tue, May 12, 2015 at 10:31 AM, Haoyi Li <[email protected]> wrote: >> >>> > Dependencies are not declared, so are hard to track for big cakes. >>> >>> Only true if you don't use https://github.com/lihaoyi/acyclic! >>> >>> I'm sure you're sick of me pitching my library, but banning circular >>> dependencies between files solves exactly this problem. You can not longer >>> take a dependency on *Global* on every single *Slice*, because *Global* needs >>> a dependency on every *Slice* in order to extend it. Thus you are >>> forced by acyclic to keep each slice only depending on the smaller slices >>> that you truly need, in a controlled fashion, or explicitly spelling out >>> dependencies into abstract members. This solves your problem entirely. >>> >>> > - If cakes contain types, these can be accessed from outside the >>> cake only with path dependent types. Cakes with mutual type >>> dependencies between them (as they exist in nsc) are particularly hard >>> to model. >>> >>> I feel that this is more a problem with path-dependent types rather than >>> with cakes. This is true, but you can often avoid path dependent types in >>> many scenarios by declaring all your "real" types/interfaces outside the >>> cakes, and then the cakes become a lazy way of doing constructor injection >>> (2 lines per file, rather than 1 per class) without any of the weirdness >>> you find in tools.nsc.Global >>> >> >> The path-dependent types in Global have path-independent traits (e.g. >> Tree.TreeApi for Global.Tree). >> >> Best, Oliver >> >>> >>> >>> >>> On Tue, May 12, 2015 at 1:22 AM, martin odersky <[email protected]> >>> wrote: >>> >>>> I would not classify cake as an anti-pattern per se. Like any scheme >>>> it is good for something but can be over-used. In fact, cake and >>>> inheritance are quite similar in their benefits and problems. >>>> Here are some points I can think of (I'd be interested in other >>>> arguments people might have). >>>> >>>> The good: >>>> >>>> - Lets you compose multiple components quickly and with minimal fuss >>>> - no parameters, no forwarders, no imports, just mix slices together. >>>> >>>> - Allows for mutual dependencies between slices. >>>> >>>> - Is therefore very general: Any set of global definitions with >>>> arbitrary dependencies between them can be lifted into a cake. >>>> >>>> The bad: >>>> >>>> - Because they are so convenient, cakes tend to get big. >>>> >>>> - Dependencies are not declared, so are hard to track for big cakes. >>>> >>>> - If cakes contain types, these can be accessed from outside the cake >>>> only with path dependent types. Cakes with mutual type dependencies >>>> between them (as they exist in nsc) are particularly hard to model. >>>> >>>> In summary, cakes, like inheritance, are a useful tool to achieve >>>> close coupling of components. It's very easy to link components in one >>>> cake, and it is comparably much harder to access them from the >>>> outside, in particular if types are involved. Cakes are misused in a >>>> situation where weak coupling is preferable (and those situations are >>>> in the majority). >>>> >>>> My advice would be: Cakes are fine to model mutual dependencies >>>> between traits. However, care must be exercised to keep them >>>> reasonably small. Furthermore, one should think twice whether >>>> embedding types in cakes is the right way to model things. Nowadays, >>>> I'd do that only if the type was essentially private to the >>>> participants of the cake, or if it was clear that every instance needs >>>> its different opaque type. Otherwise one might end up with awkward >>>> situations, where e.g. the type of symbols in the nsc compiler depends >>>> on the cake that's used. Sometimes you want that isolation, but at >>>> other times you want to communicate a symbol between different >>>> compiler instances (i.e., cakes), and then all you can do is copy an >>>> arbitrary complex graph of symbol dependencies (see the "Importers" >>>> framework in scala.reflect). So, putting types in traits can be a >>>> premature restriction of their usage. >>>> >>>> The alternative to cakes is essentially functional abstraction. Have >>>> components parameterized by others. Depending where you come from you >>>> might call that "functors" or "constructor dependency injection". >>>> Implicit parameters can help reduce the boilerplate in function >>>> application. >>>> >>>> The dotty compiler uses fine-grained functional abstraction >>>> everywhere, using implicit context arguments. That has turned out to >>>> work quite well so far. Contexts are still cakes, in that they mix >>>> together slices that are modelled around different concerns. But they >>>> are much smaller and tend not to contain types, just methods and >>>> fields. >>>> >>>> This writeup got much longer than I meant it to be when I started... >>>> >>>> - Martin >>>> >>>> >>>> On Tue, May 12, 2015 at 9:13 AM, Alex Ivanov <[email protected]> >>>> wrote: >>>> > Good morning everyone. >>>> > >>>> > I’m very interested in the topic of modularity in Scala. It’s not a >>>> secret >>>> > that today The Cake Pattern is the most popular way to achieve >>>> modularity in >>>> > the project and, to some extent, a nice way to manage dependencies. >>>> On the >>>> > other hand this way of structuring the application becomes more and >>>> more an >>>> > anti-pattern, but unfortunately there’s not much explanation why. I >>>> feel >>>> > that it’s pretty hard to answer why it’s becomes an anti-pattern >>>> without >>>> > some big, active project (like Scala compiler), but in general i can >>>> think >>>> > of things like - complicated design, not that nice way to manage >>>> > dependencies, problems with binary compatibility, slower compilation >>>> due to >>>> > inheritance overuse and complex cyclic dependencies, any other issues >>>> that i >>>> > didn’t think of? >>>> > >>>> > I remember that not so long ago Prof. Odersky mentioned he was also >>>> > disappointed in the pattern and went a bit different way with a Dotty >>>> > design. But, unfortunately, i couldn’t find details on this decision, >>>> what >>>> > were the problems and how they were solved with a new design (would >>>> be good >>>> > to read a paper like Scalable Component Abstractions). Anyway the >>>> project is >>>> > open-source, so it’s not hard to take a look and see that there are >>>> some >>>> > differences in the design, some components are packed within >>>> modules/objects >>>> > and it uses less cake-style coupling (beside the Context structure). >>>> Could >>>> > someone please unveil the secrets of the dotty architectural design? >>>> > >>>> > And, i guess, that last question that bothers me, what to use instead >>>> of the >>>> > Cake? In the talk “Scala - the simple parts” i liked the idea on the >>>> Scala’s >>>> > Modular Roots where we can see the mapping between Scala and SML >>>> languages. >>>> > Can’t reason much on this, i’ve just started looking at what we can >>>> achieve >>>> > with this SML-style modularity (maybe someone could explain this as >>>> well =)? >>>> > ), but it looks like a better approach to the modular design, >>>> especially in >>>> > combination with typeclasses. Of course we should “use the right tool >>>> for >>>> > problem”, but it feels like the Cake Pattern, is not good as the >>>> essential >>>> > approach to the application architecture and modularity. >>>> > >>>> > -- >>>> > 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. >>>> >>>> >>>> >>>> -- >>>> Martin Odersky >>>> EPFL >>>> >>>> -- >>>> 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. >>>> >>> >>> -- >>> 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. >>> >> >> >> >> -- >> Oliver Ruebenacker >> Solutions Architect at Altisource Labs <http://www.altisourcelabs.com/> >> Be always grateful, but never satisfied. >> >> -- >> 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. >> > > -- > 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. > -- Jon Pretty | @propensive -- 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.