6 ms·
I don't think it matters how good or bad C# is, Object Oriented Programming is a mess Learning, how to use an Object System (a tree of objects/classes) is inhe
by systems 3y ago
I don't think it matters how good or bad C# is, Object Oriented Programming is a mess
Learning, how to use an Object System (a tree of objects/classes) is inherently hard
The current problem with F# is that it doesnt do enough to shield you from objects, it does what it can, but still to use F# effectively, you still need to learn some C# and a lot of API that basically Objects inside Objects inside Objects calling Objects calling Objects and more Objects
OOP is bad because eventually OO systems becomes too complex, OO API is intimidation
Separating Data from Behavior manages complexity better
If the only flaw in C# is knowing which method calls requires the new keyword because its a constructor, and which dont because its a factory, that is bad enough to want to avoid it
- CrimsonCape 3y agoI 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.
- heywhatupboys 3y agowell 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
- epgui 3y agoThis comment shows a total misunderstanding of what functional programming is…
- heywhatupboys 3y agoWhile tongue in cheek, this is one if the OP in non-OP patterns that is used heavily for large projects in FP alike.
- epgui 3y agoI'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.
- tigershark 3y agoThis 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.
- epgui 3y agoNot 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.
- systems 3y agorelational 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
- CrimsonCape 3y agoYes, 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-ispace.html https://www.nytimes.com/2023/05/26/science/moon-crash-japan-...
- Const-me 3y agoDocuments 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?
- tcfhgj 3y agoIt'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
- el_oni 3y agoSounds 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?
- tcfhgj 3y agoThe 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.
- pharmakom 3y agoThe 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.
- ThinkBeat 3y agoEvery system if allowed to become too complex. No single paradigm of programming is perfect for all cases. OO is one way to structure and model a system. No matter what language you use will end up with some form of a struct, a set of values that belong together Then you will have list of some structs and trees of some structs You will almost certainly have to create list/collections/groupings of structs. Because those are quite useful and universal How you act on those collections is different between different idioms. In other words you will create a model of data one way or another and you have to maintain it / change it, as required over time. The data structures themselves are rather often based on or more database schema where the data will be extracted and saved.
- rgbgraph 3y agoJust like every language is able to be slow/non-performant -- but OO in this case would be Python in a web context; it doesn't invalidate that a good amount of OO codebases in the wild devolve into incomprehensible black boxes, where no one has any idea what anything does or how to make meaningful changes that fulfill the intent of (compare that to iterative programming, where you can atleast read it) A list: I give you a vector. Plain and simple. Not this insanity: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646 https://referencesource.microsoft.com/#mscorlib/system/colle... [0] You do not need OO to create a vector (or even an array -- god forbid!) As for trees: roll your own. They're simple enough, yet tightly-coupled with context that no generic implementation exists that is flexible enough. You do not need OO to create a tree. C has been working with trees long before the current Frankensteination of OO was even a twinkle in Gosling's eye.[1] Data structures do not need inheritance -- they might need delegation (message passing that requires you to actually think about your system). Data structures do not need encapsulation -- they most likely need namespaces. Realistically, most classes will be used as namespaces. Data structures do not need polymorphism -- just implement the members you need, and name them appropriately (no 5+ word phrases, please. Please!) What modern OO does is lower the barrier to productivity in the present, and then pays for it in the future. It's no different than writing your "planet scale" backend system in JS. [0] Compare to: https://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a01115_source.html https://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a0111... [1] If you want to know why we have Java: some guys that didn't have the time to think about low-level (memory management specifically) things for their embedded applications, got sick of trying to learn C++, decided to make their own language. That's it. There was no grand plan or thoughtful design -- it's just a mismash of personal preference. The same people that described C++ as "being too complex" (fair) and using "too much memory" (lol)
- devmunchies 3y agoThe worst part of OOP is that all the properties of an object can be a mishmash of values and are mutable. In any method, you never know if the object is in some undesirable state without checking properties within the method itself. Multiply that headache across all methods and all other classes and it becomes a mutable mess. It makes it weird that we pass around objects as types when they encapsulate so much state and logic. They aren’t really a concrete data types, they are an entire living village. With functional languages, it tries to enforce some explicit type signatures in the function arguments so things are cleaner within the functions themselves.
- UncleMeat 3y agoThis isn't a property of OOP. This is a property of poor class design. You absolutely should be designing classes such that every possible sequencing of their public methods leaves them in a valid state and maintains their invariants. Structs have the issue you describe and they aren't really OOP. Yes, if the first thing you do when you write a class is make a setter method for each field then you will have problems. That's not really a property of OOP.
- devmunchies 3y agoPoor class design IS a property of OOP. All of these logical errors that are easy to commit are terrible because they are usually runtime bugs, not compile time. As I think of it, I think a neat feature of OOP would be conditional methods that are only callable under specific circumstances. For example, the “Customer.SendPasswordResetEmail()” method couldn’t be called (or didn’t even exist) until I verify that the “Customer.IsEmailVerified” property is true. Being able to add these type of annotations to methods for expected object state would help catch some logic bugs at compile time.
- pjmlp 3y agoLisp derived languages, with dynamic gradual typing, and dynamic scopes, say hello.
- magicalhippo 3y ago
- lelanthran 3y ago> OOP is bad because eventually OO systems becomes too complex, OO API is intimidation This strikes me as a sort of ... reverse of survivorship bias. You look around and see all complex systems are in OO, then you conclude that it is OO that is the cause of the complexity. Have you considered that the non-OO designs are deficient in some way that prevents them from being used for the type of systems that you find to be examples of OO being bad? Not that I am defending OO, I just want to know how you are differentiating between "OO produces complex systems" and "OO is used for complex systems".
- jacquesm 3y agoOne of the main issues with this is that OO as practiced in C# and Java is only a very thin extract from the real OO as provided by for instance Smalltalk. And without that kind of environment you end up with the worst of both worlds, where you have an OO like interface layered on top of things that aren't really objects to begin with, because they aren't 'alive'.
- aksss 3y agoVery good observation but I do wonder whether it’s the worst of both worlds or the best of both worlds - more the “eat the meat and spit out the bones” approach?
- xmcqdpt2 3y agoOne might say that Real OOP has never been tried.
- whstl 3y agoThere's Smalltalk. And Ruby gets pretty close to Smalltalk, but yeah, in practice it ends up looking like very close to Java. Your point stands.
- pmontra 3y agoErlang and Elixir with spawn processes (objects with their own CPU) and send / receive message passing? But they do their best to hide it in OTP behind all that handle_* boilerplate.
- Zecc 3y ago>If the only flaw in C# is knowing which method calls requires the new keyword because its a constructor, and which dont because its a factory, that is bad enough to want to avoid it I'm sure this is just an example popping first out of your mind, but it seems like an oddly specific thing to mention. Specially since the answer is obvious if you know C#: the name of the method matches that of the type if and only if it is a constructor. I won't comment on the rest of your post as my experience with F# is minimal; but I think I understand where you're coming from. > Separating Data from Behavior manages complexity better There's a sweet spot, and it varies. Sometimes it is difficult to find. API design can be difficult. Managing complexity is sometimes itself a complex process.
- pjmlp 3y agoIt is a mess, become most people don't learn how to code properly. They would make a mess in Modula-2, or Standard ML as well, given how many need a network layer to write modular code.
- seanhunter 3y agoF# (and ocaml, on which it was modelled) are oop languages. If you don’t like oop there are functional programming languages that might be better fit for you.
- revskill 3y agoNo, Functor, Monad is OOP concept.