Re: [scala-language] The cake’s problem, dotty des ign and the approach to modularity.
martin odersky <[email protected]>
| Newsgroups | gmane.comp.lang.scala |
|---|---|
| Message-ID | <CAENVNkb3tm5kQG4t_R1bFf0hTB=R=5cf1VXj4NtXb61HWMAEpA@mail.gmail.com> |
On Tue, May 12, 2015 at 8:19 PM, Haoyi Li <[email protected]> wrote: >> But if you ban circular dependencies you don't need a cake - you can >> just use normal inheritance. A strong point of cakes is for me is that >> they support circular dependencies. Also, even if your dependencies >> are non-circular, and even if you just use plain inheritance, >> dependencies are still sometimes hard to track because there are no >> explicit declarations what they are. > > You can ban circular dependencies within files without banning circular > dependencies at runtime, by ensuring that the circular dependencies depend > on abstract methods! > Sure. But the core part of nsc has circular dependencies between types: Symbol depends on Type and Type depends on Symbol, and each is in its own (rather large) trait. That cake supports this is both its strength (because it is a very general composition mechanism) and its weakness (because it invites abuse). Cheers - Martin > e.g. ScalaParse's Literals.scala has a circular dependency on Scala since > you need to be able to parse anything in the world to be able to parse a > string literal (lol) but it's kept as an abstract def and only filled in > when the cake is put together. As you can see, you get the circular > dependency we want, together with a well-designed interface and controlled > circularity/ugliness, all because Acyclic forced us into this shape. > > If the abstract defs start getting annoying due to repetition over and over > at the top of every trait, pull them out into their own trait! Maybe you no > longer consider it a trait when the self-type is an totally-abstract > interface-trait and not some concrete Global trait, but it's really the same > except without the circular dependency hell. > > I agree it is very easy to fall into the "everything depends on everything > else" trap that scala.tools.nsc.Global is in. Scalac will not complain. > Acyclic, on the other hand, will not let you! In fact forces you into the > "well designed interfaces" whether you like it or not =D > > > On Tue, May 12, 2015 at 10:58 AM, Jon Pretty <[email protected]> wrote: >> >> 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 >>>> 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. > > > -- > 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.