Hacker News new | ask | show | jobs
by CrimsonCape 1121 days ago
I empathize with your characterization of "a tree of object/classes" and I yearn for an example of how else to model a complex, domain-specific system not using the aforementioned tree.
5 comments

Not the author of the comment, but based on how I understand the comment, I feel essentially the same way.

I would characterize it a bit differently, seeing as, for example (and to your point), a purely functional lisp program is a tree of lambdas and macros. The same could be said of Haskell.

For me the issue is that classes and objects are actually pretty complicated things for what they are. It’s easy to not notice when you’re in the habit of using them, but really pause and think about how complicated they are. They have both structure and machinery that probably aren’t required for most abstractions: regardless, in OOP they get shoehorned into every problem.

This is why OOP ends up with a bunch of well known design patterns, whereas in FP they’re not reaaaaally a thing (arguably).

A tree of functions is probably the simplest possible way to build programs, at a fundamental level: I am not speaking in terms of individual preferences here, but really mathematical simplicity.

well you see! What we can do is to namespace our functions, e.g. by naming them component_create, component_add_button, etc. We then create a plain dictionary with key value pairs that gets passed onto these functions! The functions then possibly return a new map, which is a modified map! This allows us to write code like

  dog = dog_create({name: "foo", age: 12})
  dog = dod_add_friend(dog2)
  print(dog["friends"])
and we can avoid OO completely.

oh... wait a minute

This comment shows a total misunderstanding of what functional programming is…
While tongue in cheek, this is one if the OP in non-OP patterns that is used heavily for large projects in FP alike.
I'm not seeing that in the example, and I'm not even seeing anything very relevant to FP in the example either. I guess there isn't much mutation happening, and functions are called? But that's not what FP is.
This tells me that you never really looked at functional languages, not even used them. The power of ADT, especially when using a comprehensive pattern matching expression, is pretty difficult to emulate in the OOP world without a ton of code. But in this extremely simple case you just need a record.

    let dogBar = {Name = “bar”; Age = 11; Friends = []}
    let dogFoo = {Name = “foo”; Age = 12; Friends = [dogBar]}
    printfn “%A” dogFoo.Friends 
The advantage is that it’s immutable and it’s guaranteed to don’t have null in any fields. C# only introduced records recently, while F# was born with them. And C# still hasn’t got ADT because it’s missing the Union types as far as I remember.
It's not a tree though. A tree doesn't have connected leaves and branches. This is, however, common with classes that might get injected the same dependency
Sounds like missing the tree for the forest. Im not from a pure cs background (so forgive my mangling of terms) but isnt a tree essentially an acyclic graph with constraints, 1 parent 2 children for example? What you're describing is adding some cycles into that graph no?
The number of children can be anything, it's two children for a binary tree. Each node except one node must only have one parent, which isn't true if two or more nodes share one or more children.

And, yes, in theory this adds cycles which aren't allowed. However, since class dependencies are better represented as directed connections (which aren't usually used for trees in CS terms), it isn't a true cycle.

relational model, like we always did and do everyday (in the db realm)

i am not saying we should not use trees ever, i am mainly saying, when the model is a very deep tree (or several deep trees and trees everywhere), its becomes overly complex

data models should be as flat as possible , and only nested when absolutely necessary

Yes, and my yearning was for examples in which the domain objects are complex systems or machines themselves.

To your point, if the domain is a payment system, I can keep separate db's of Customer Info, Customer Purchases, Transaction Instances, Customer payment methods, etc. This seems like a domain suitable for functional code.

If the domain is a two stage orbital rocket, in which we must have a stateful system that has internal feedback loops (fuel consumption, vehicle trim, time of flight, time before stage separation, engine sensor data), our best software design is an object graph which causes spaghetti code ( does the navigation system belong to the electrical system, or the radio system? Wait, does the radio system belong to the electrical system? Wait, does the entire electrical system belong to the solid fuel system, since the electrical system is dependent on the generators partially, but what about the battery system? What critical components stay on the battery system if the generators are shut down?). I guess my point is, real life is a spaghetti relationship.

Consider the recent ISpace probe crash. The article says "software bug" but in reality it's more of a 'design flaw' and I would bet it's exactly because of the topic of this thread. The sensors were reading correct data, but the design/validation of the intercommunication data between sensors was designed wrong.

https://www.nytimes.com/2023/05/26/science/moon-crash-japan-...

Documents are pretty much everywhere. In many cases they are mutable because user needs to edit them, and on the web JavaScript code needs to dynamically modify them.

According to debugging tools in my web browser, your <div class=comment> is at level #15 under the <body> element. I wonder how would you model the in-memory representation of this web page, while keeping the model practical?

The big difference between C# and F# styles (yes you can do either style in both languages, but with varying degrees of friction) is if that tree is mutable or immutable.