6 ms·
The solution to incremental changes is to develop your app in a way where every unit of computation is compose-able under a strict rule. Meaning I can write a u
by crimsonalucard 7y ago
The solution to incremental changes is to develop your app in a way where every unit of computation is compose-able under a strict rule. Meaning I can write a universal function compose(A,B) = C and that function can compose any primitive. Then you build complicated logic just like how you build a wall from a set of bricks... form complicated logic as a composition of more primitive logic all the way down.
If your program is constructed this way at every layer of logic, not only will your program be amenable to append only styles of programming. But it will be amenable to decomposition. Often you find that your primitives are too big and you need to split your primitives... well if your primitives are itself made out of the compositions of lower level primitives then breaking apart that function is trivial.
There is only one primitive in all of programming that follows this composition rule. Procedures cannot compose, Objects cannot compose. What's left?
- yellowapple 7y ago> if your primitives are itself made out of the compositions of lower level primitives I'd argue those ain't "primitives" in that case; what differentiates a "primitive" from some other kind of computation is that it can't be broken down further. > Procedures cannot compose Depends on how you define "procedure". In the sense used in procedural programming, you certainly can compose them (i.e. by jumping into a subroutine that in turn jumps into other subroutines, pushing and popping things to/from the stack in the process). This is a pretty fundamental concept for threaded interpreters, and Forth in particular (as well as other stack-driven concatenative languages descended from it) exemplifies this as the very basis of the language itself. > Objects cannot compose Object composition (both by including objects within other objects and by using interfaces and implementations thereof) has been a thing for multiple decades now.
- crimsonalucard 7y ago> I'd argue those ain't "primitives" in that case; what differentiates a "primitive" from some other kind of computation is that it can't be broken down further. Usually when you program you don't create a library made out of the lowest level primitives. You start out with higher level primitives and hopefully if your design is correct, all upper layers are different compositions of this lowest level set of primitives. I am talking about this layer of primitives. If you chose your primitives incorrectly and find out that you need to break apart your primitives, it is far easier to do this if your primitives themselves were also made out of compositions of lower level primitives. If your primitives were already a tangle of objects and procedures this would be very hard. >Depends on how you define "procedure". In the sense used in procedural programming, you certainly can compose them (i.e. by jumping into a subroutine that in turn jumps into other subroutines, pushing and popping things to/from the stack in the process). This is a pretty fundamental concept for threaded interpreters, and Forth in particular (as well as other stack-driven concatenative languages descended from it) exemplifies this as the very basis of the language itself. I defined what I mean by composition. By procedure I mean a list of procedures of instructions. What does it mean to compose steps One through five with steps six through ten? Is steps six through ten compose-able with another set of steps from a whole different sub routine? Most likely no. You cannot define a singular function compose(step1, step6) = step4 like I described in my definition. >Object composition (both by including objects within other objects and by using interfaces and implementations thereof) has been a thing for multiple decades now. Does this fit with what I defined as composition? No it does not. Object composition is a horrible word. It is not true composition. Dependency injection is a more fitting word for what is actually happening. You are making one object depend on another object, you are not composing two objects to form a new object. When objects "compose" you create dependencies and custom glue code to make everything fit together. When I refer to composition I am talking about how bricks compose to form a wall. There is only a singular form of composition to compose bricks into a wall and each brick can exist without a dependency to another brick. "Object composition" is using as much concrete as possible to compose bricks of every geometric shape into a mishmash ball of solids. Again objects and procedures do not compose like bricks. Another programming primitive is more suited for this. Maybe someone knows what this primitive is.
- yellowapple 7y ago> You start out with higher level primitives Those aren't primitives, though. Primitives are the lowest possible level; that's what makes them primitives. If something can be decomposed further (or is in turn composed of other things which are visible to the language without e.g. dropping down to assembly), then it is definitionally not a primitive. I think the word you seek is "components". > By procedure I mean a list of procedures of instructions. That's a circular definition, and does not in any way clarify what you mean by "procedures". > What does it mean to compose steps One through five with steps six through ten? In the context of procedural programming, it would ordinarily mean to perform those steps in sequence (that is: the output of steps one through five would be the input to steps six through ten), or to define a procedure which in turn calls those procedures in sequence. > You cannot define a singular function compose(step1, step6) = step4 like I described in my definition. In pseudo-Forth (with punctuation turned into something more reasonable, and a couple imaginary procedures for creating (anonProcedure) and executing (execute) function pointers): procedure stepOne anonProcedure finely chop end end procedure stepSix anonProcedure pan add stir end end \ [pop] is imaginary and purely illustrative of the idea of \ taking function pointers off the stack. procedure compose anonProcedure [pop] [pop] end end procedure stepFour stepSix stepOne compose end chicken stepFour execute \ equivalent to: chicken finely chop pan add stir Looks pretty composed to me. > you are not composing two objects to form a new object class Foo { greeting = "Howdy" hi = { puts $greeting } } class Bar { farewell = "Adios" bye = { puts $farewell } } class Baz { greeter = new Foo dismisser = new Bar hi = greeter.hi bye = dismisser.bye speak = { hi; bye } } speaker = new Baz speaker.hi # "Howdy\n" speaker.bye # "Adios\n" speaker.speak # "Howdy\nAdios\n" Tada! > When I refer to composition I am talking about how bricks compose to form a wall. You're talking about doing it in a way that assumes you're only allowed to use bricks on their own, piled high with noting actually connecting them together. Procedures and objects work great as bricks. You just need some mortar and rebar. > Maybe someone knows what this primitive is. Maybe you'd do a better job conveying your point if you just said the "primitive" you mean instead of being needlessly coy about it. And regarding this brick-which-cannot-be-named-for-some-reason: yes, they happen to snap together remarkably well like Lego bricks, but people don't (typically) build their houses with Lego bricks, nor do people normally write their business logic in Haskell.
- quickthrower2 7y agoWhats Left? Functions! compose(f, g) = \x -> g(f(x))