HNHacker News
TopNewBestAskShowJobs

deltaonefour

694 karma · joined July 23, 2021

I work at anduril. I'm also really tall.
submissionscomments
deltaonefour··on ‘Blade Runner’ at 40
Great. Then you're not the elitist group I'm referring too. I'm basically talking about the difference between MCU style blockbusters and br. The pacing is a huge delta.
deltaonefour··on ‘Blade Runner’ at 40
If you were mature, you wouldn't insult people and call them immature lol.

Maturity isn't even a legit concept. People are all very different. The word immaturity more or less is used here as venom. Direct insults.

So why do you want to insult me? Why flagrantly violate the rules of HN if your so mature?

deltaonefour··on ‘Blade Runner’ at 40
See this here with more French when I obviously called you on it is called trolling.

Nobody look up that French or ask about it... it's a trap so he can lord it over you with an authoritative expose and explanation of his expansive knowledge of French wisdom while eating a croissant.

deltaonefour··on ‘Blade Runner’ at 40
It's not a fight, it's a discussion.

The magic stuff actually has (or had) sort of a background explanation based in "science" so overall I would say it's more sci-fi.

In many cases I would even argue genres like sci-fi and fantasy don't involve the plot at all. These genres exclusively refer to the setting.

deltaonefour··on ‘Blade Runner’ at 40
Yeah. The pacing on that is even worse.
deltaonefour··on ‘Blade Runner’ at 40
No it's not pretentious at all.

What I find pretentious is when you love the slower stuff but hate all the popular stuff and dismiss pacing as even a relevant factor.

Many many people have this attitude and they actually dismiss MCU stuff as raw garbage, too base level for their intellectual tastes.

I repeat. Your post is not pretentious to me at all. It's what I come here for. Thank you.

I agree with you there are movies that require a huge slow as hell build up in order to deliver a huge pay off. I agree and I like those movies despite the slow pacing. But those movies imo would benefit from better pacing regardless. I've seen people quit watching before the payoff and forever have their opinion of that movie forever tainted.

deltaonefour··on ‘Blade Runner’ at 40
Lol we both know the intention here was snobbery. Just reference the painting in English instead of communicating with terminology everyone has to Google.
deltaonefour··on ‘Blade Runner’ at 40
Bro. I'm older then you. Lol.

Your very narrow minded to assume that just because someone has a different opinion then you it's from a person younger then you.

In fact talking to someone in such a patronizing tone isnt itself exactly the overly polite tone dang seems to ask for from users on HN. I offer hard controversial opinions with no cushion, you treat me like a child lol. We are both bending the rules here.

If you ever raised a child past his teens, you will know treating a teen like a child, patronizing him is not only a surefire way of making that person your enemy, but it's also wrong and in itself very immature. Shit like "it's ok to be curious and immature when your young" is raw venom cleverly disguised as advice. I will tell you the truth. By saying shit like this you display both immaturity and you show that you are manipulative. Immaturity can be "fixed", manipulation cannot. Don't fuck with me bro.

>BTW, if you share a Chinese saying that people can Google and be educated and delighted by, I think it would be welcomed. Even in Chinese.

The proper way to do this would be to share it in English, and explain it. Thats proper communication. Leaving it in Chinese and expecting you to Google it is a very unnatural thing to do by someone who's intention is to communicate. So obviously there's a secondary intention here.

What this person is doing raw snobbery. You just happen to likely agree with this persons initial opinions on blade runner and the MCU, so during your little team up here your supporting his every move his every tactic, however obviously snobbish.

My tip for you is to always stay neutral. This is the internet so unique to the internet you can take a position where you Have no allies and have no enemies and only offer your raw opinions for everyone to agree and disagree with. At times everyone can disagree with you, at other times everyone agrees with you.

If you find that everyone is agreeing with you all the time... then you're just not a very original person and your not learning anything.

When I offer a controversial opinion occasionally I'm flipped. I'm changed. The other side convinces me and my entire outlook on a topic moves to another dimension. That's what I live for and that's why I offer hard hitting opinions. Because I want people to offer them back.

deltaonefour··on ‘Blade Runner’ at 40
>He's referring to a painting. https://en.m.wikipedia.org/wiki/The_Treachery_of_Images

Most people don't know about this painting nor do most people know French... I'm sure you and him are aware of that.

It could be that whatever the painting represents fits his point. But you have to look deeper then that because he is fully aware that most people on this site don't know about that painting nor do they know French. So why post it at all? His intent definitely wasn't communicating anything understandable to anyone here.

I'm Chinese, so if quoted some famous quote from Confucius, and to top if off I wrote that quote in Chinese, then of course my intention isn't communication. I know most people on HN can't read Chinese, so then why would I include the quote?

I would have included it to make myself look intelligent, educated and well versed in Chinese philosophy. This is basically the gist of what's going on here.

The alternative is he just didn't have the brains to realize this is an English site and most people don't speak french nor do they have an understanding of French paintings.

I would say the former reason is much more likely then the later.

That's why I said it's almost like a cartoon. I'm talking about elitism in movie tastes and here someone tries to counter that claim with a carbon copy circus act of exactly the snobbery I'm talking about. I don't think he picked up on it, and hopefully this explanation helps you realize what I'm talking about.

deltaonefour··on ‘Blade Runner’ at 40
>That's not an argument, that's a conclusion without any supporting arguments. Dismissed as nonsense as easily as posited without effort.

This is HN not nature. It's not a scientific debtate, just a general conversation so the level of proof is not super high.

You just have to trust me that I'm born in China, and Fantasy is not Wuxia. Just like you would have to trust a black person when he says he's not white. Don't go calling a black person white and don't go around saying you can move fucking star wars into Ancient China to a Chinese person who knows the culture and the genre.

Actually don't listen to me. Go ahead and say whatever you want to people. When a black person tells you he's not white, demand a scientific inquiry to prove he's black.

Either way agree to disagree. I think star wars if sci-fi. You don't.

But I will say, if you ask most people, most people will say star wars is sci-fi. At least we can agree on that point.

deltaonefour··on ‘Blade Runner’ at 40
> A quality that makes a film commercially successful is not automatically a quality which makes a film great art.

Agreed? Why are you telling me something I completely agree with?

>Popular is popular. Art is art.

The problem here is that for people like you, most of the time:

"Popular is NOT art",

it's this elitist attitude that "art" is above what is "popular" that I hate. We divide wealth into classes and now we have to divide tastes. Looks like your part of the 1%.

>Ceci n'est pas une pipe.

May I ask why you decided to write some stuff in French for no fucking reason? Pretty low likelihood that I'm French or readers on HN are French so what's your goal here with putting some French here?

It's like a cartoon. You're not trying to sound elitist but your genius French kinda shows the world how elitist your headspace is. Wow French!, we're dealing with a true art critic here folks.

deltaonefour··on ‘Blade Runner’ at 40
Remember, it's "elitist" because the people who think this way are in the minority. Your and my preferences are actually the norm, just not in this thread. Most people will get bored and that is completely normal.

Although I will say that I can empathize with why people like blade runner. The good parts are good, but the mainstream audience just places a higher bar on pacing.

I also suspect that many people in the "elitist" group also get bored. They just don't admit it.

deltaonefour··on ‘Blade Runner’ at 40
No it's not. You're just getting too technical. Star wars is science fiction.

Because in the same vein you could call LOTR science fiction too because the fantasy elements are just natural properties of the created world. The "magic" can technically be technology as well.

deltaonefour··on ‘Blade Runner’ at 40
Starship troopers was a masterpiece. Don't mock it.
deltaonefour··on ‘Blade Runner’ at 40
But if you replaced the setting with a mundane one the movie would be a generic film noir.

It only works because of the combination of the setting and the story.

deltaonefour··on ‘Blade Runner’ at 40
There are three things that are important to the movie.

   - Pacing so you don't get bored. 
   - Thematic depth
   - Atmosphere
A lot of pretentious people like to ignore pacing as if their brains are made up of pure IQ and anything related excitement is beneath them. Make no mistake, we are all human and we all get bored. Pacing is important and it takes a lot of effort (and intelligence) for a director to maintain that level of momentum for a movie.

Let's face it, Blade runner really screwed up with pacing. Ultra slow pacing is understandably sort of required for the atmosphere but while it scores very very very highly in the other areas; there is absolute truth to the statement when someone says that movie is in general quite slow and boring. If your brain is too big to comprehend why Blade runner even has the possibility of being boring then I'm likely too stupid to be communicating with you, you should go read other comments of higher intelligence.

The MCU scores highly in pacing and probably is the greatest paced franchise of all time, with 10 years of momentum and a payoff unlike anything ever seen before in cinema. But because of pretension, in general a certain crowd looks at the entire franchise with disdain; even though it's actually much harder and challenging to create good pacing then many of the more serious thematically deep movies I've seen out there.

Inception would be movie that on average has the best high balance on all three pillars. Good pacing, thematically deep, well established professional/corporate atmosphere. Though I would say in terms of theme and atmosphere, while quite high, it's not quite high enough to get past certain pretentious attitudes. I would even argue that sometimes if the pacing is too good, the movie becomes too popular and thus "not good" to the elite crowd.

At the same time, sometimes if the pacing is too good, the themes and atmosphere get copied by dozens of other movies. The audience sees too much of it and becomes more sophisticated. Now the stuff that use to be high concept to the general audience becomes quite boring. Directors and movies producers are always playing catch up to increase sophistication and bring you stuff you've never seen before.

@duxup, I think this is what's happening to you. Bladerunner is so boring that it wasn't copied too much. But the other sci-fi stuff get copied to hell and now the cookie cutter sameness doesn't do it for you anymore. So you turn to the thing that's most different.

deltaonefour··on ‘Blade Runner’ at 40
Blade runner isn't even that good, thematically. But I get why it's considered the best.

It's because in most sci-fi movies a lot of effort is spent on the setting and thus the story while many times is good, often lacks the depth of their non-fiction counter-parts.

Bladerunner is one of the few movies that has blockbuster level visuals while maintaining a very serious story with a lot of depth. Gattaca is another sci-fi movie that achieves this as well, though the visuals in Gattaca aren't blockbuster level.

deltaonefour··on Revisiting the principles of data-oriented programming
Polymorphism and encapsulation are not features exclusive to OOP.

Isomorphisms exist everywhere. You could say nothing is OOP because it compiles into assembly anyway where pretty much all those concepts don't even exist. You can even say all of assembly can decompile into OOP so everything is OOP.

Think about it. If linus torvolds hates OOP. What is it that he hates? You can say, Linus is an idiot and everything is OOP so he's wrong.

Or you can understand what is it about OOP that he hates and understand the delta between my examples and what is traditionally thought of as OOP.

None* of my examples contain a class. That should be a hint, as that syntax is pretty much used in most OOP languages.

*React still contains class based components except the creators now recommend moving away from class based syntax to functional components.

deltaonefour··on Revisiting the principles of data-oriented programming
> Code is itself data, so a full decoupling is logically impossible.

Nah, code exists in a different universe then "data" and it's decoupled by default. Runtime data is completely unaware of "code." that is unless you do something called "reflection" which is sort of a rarely used feature.

deltaonefour··on Revisiting the principles of data-oriented programming
If you have a hard time thinking this way then you really need to try other paradigms in coding because OOP is not the only way and it is getting less and less popular.

For example C, is not OOP. Linus Torvalds hates OOP, so linux is in written in C. Go was created by Robert Pike who's also subtly against it, and it shows in the language. Additionally Rust pretty much gets rid of objects as well. React is also moving away from class based representation of components.

These are just modern languages that are moving away from OOP. In addition to this... behind the modern languages there's a whole universe and history of other styles of programming.

Not against OOP... But I'm saying it's not a good sign if OOP is the only perspective you're capable of seeing.

deltaonefour··on Revisiting the principles of data-oriented programming
Most things in programming aren't formally defined. It is especially hard given the isomorphisms everywhere.

At best what I've done here is eliminate some of the vagueness surrounding the definition, which is really all that's needed in most cases.

deltaonefour··on Revisiting the principles of data-oriented programming
One way to define it is to look at the thing that's unique to OOP that isn't used in any other paradigm.

In OOP data and method are unionized into primitives that form the basic building blocks of your program.

This is unique to OOP. It must be the definition. Defining it in terms of message passing, encapsulation and inheritance are not as good because these concepts are used in other paradigms as well.

deltaonefour··on The Composition over Inheritance Principle (2020)
>I think we should focus on semantics here rather on syntax only.

We are focusing on semantics. But your definition of OOP is shaped by enterprise style syntax and languages. I'm using very general notions of OOP and general psuedo code and a general notion of what a struct is outside of something like c++.

All programming domains outside of OOP use concepts like polymorphism, inheritance, interfaces and such; they just have different names. The only thing that is exclusively a unique feature to OOP is that methods are unionized with data in scoped sectors called objects and this model is used as a base primitive of a program.

Also OOP and procedural are orthogonal. Most OOP languages are procedural. As long as you have instructions executed as a list of procedures you are doing procedural programming which is 99 percent of what's out there. FP programming is the opposite counterpart to procedural. If your program can execute on a single line as a single expression then you are not executing instructions procedurally... it is now functional. That is the essence of FP.

The strange thing though is FP is not orthogonal to OOP. Most versions of OOP involve setters. Which are methods that mutate state. That in itself makes it so no OOP program following that model can be FP.

>Objects are dividable in roughly two categories: entities/values and services.

Entities and values aka structs are not a concept from OOP. The very general notion of this concept is that these are called Product types with named access to members.

OOP is style of programming that uses Product types such that the entire program lives as part of a Product type and that product type contains State, and methods, and other Products as part of it's structure. This is what you call services. Services are basically a synonym for your standard OOP object.

deltaonefour··on The Composition over Inheritance Principle (2020)
>I don't follow, is DependencyInterface a proper interface (as in OOP)?

Interface is not part of OOP. C++ doesn't have it. It's still OOP. Interfaces are a language implmentation detail with a vague definition. In general an interface refers to a general concept called a type of types. An interface is a type of types.

But following your intent. Yes. It is an interface in the way you think of it.

>If so, then, the code appears more complicated compared to just implementing two classes SocketLogger and FileLogger which implement LoggerInterface (by providing log(...) method) and accept Socket and File in their constructors respectively (at least 1 method each) - 7 concepts so far (if we count the methods, too).

It's less complicated. LoggerInterface isn't a concept that exists in my example. Actually you can adjust my example for it to be more simple. Only impliment generalLogFunction. Then impliment the interface of DependencyInterface for socket and file. 3 concepts.

For oop you impliment two constructors, two log methods as well. That's 4 concepts.

>If DependencyInterface is a function pointer then it's not clear how it actually retrieves its socket without resorting to casting from void* (unsafe) or using global state (not thread-safe).

It is not a function pointer. This is isomorphic to the command pattern. Don't need to get into the specifics other then the fact that it's a awkward way to pass state.

>In any case generalLogFunction is global state. What if I want to use a different implementation for a different use case? As a client, I can't use this global function anymore => leaking abstraction. In OOP I'd be happy to work with whichever logger was injected into my instance.

A function definition is global state? A class is global state too. No difference dude. The only thing injected here is a dependency that is agnostic to logging. The socket itself is an interface to IO, but we use it here to differentiate between files and network, so can't talk about it in those terms but Socket is indeed an interface in itself.

>What will happen if the current global function is SocketLogger but I pass a file as a DependencyInterface?

generalLogFunction should handle it as a DependencyInterface. You need one implimentation of it, and you don't need logSocket or logFile. Sorry my example up there wasn't fully correct. The difference between how a file and a socket should be handled should not exist in the log function but in the implimentations of the DependencyInterface.

>What if the log function needs a second dependency? You have to add another argument to doStuff and anywhere where the log function is used.

This changes the signature of the interface.

>I see no benefits here, it's more complicated and more code.

If you don't understand my description then at least my example above sould display significantly HIGER compositional then OOP. I can construct more different types of entities from primitives with my approach then OOP.

>You lose static typing with this, because key/values stored in a context have to be cast from interface{} to the target type at runtime and there are no compile-time guarantees the value is present or of appropriate type. Usually contexts are used for cancellation.

It's not a key value store. It's indeed used for cancellation and the interface is created for such a purpose.

>It doesn't break the interface because interfaces don't have constructors. We do have to change the signature of the concrete class' constructor when dependencies change but method calls are far more common than constructor calls. When we change code due to new requirements we have to change something by definition, what we do is trying to minimize the amount of code which has to be modified. A method call is a more common case than an object construction.

Then do dependency injection on the method. The constructor is cheatcode that will cause a type error somewhere else. The dependency interface gets rid of this problem EVEN for the OOP version.

deltaonefour··on The Composition over Inheritance Principle (2020)
>You're doing it wrong: you pass LoggerSocket as a function argument.

This is because I'm too lazy to write out a full class definition for DI. The intent of my example still stands. I'm writing a lot, and a lot of examples too, so forgive me if I don't write out the entire DI pattern of passing ownership of the Dependency to a class.

>In a real project, the logger will already be preconstructed somewhere else (DI framework, for example, but manual initialization somewhere at startup works as well) and stored as an object field of the current class (in a functional language that would be a captured value).

Bro, just pretend that the doStuff function is a constructor and that it also happens to do more stuff then I wrote, like maybe assign it to a member variable if that helps you understand better.

>So at most of the call sites it's going to be just this.logger.log("some error happened") without any mention of sockets or any other kind of boilerplate/implementation details.

I would say the logger instance is a boiler plate detail. It's a wrapper around all the dependencies. WrapperSocket/LoggerSocket etc. Ideally what we want is just log(string). Too bad.

>Our client class has a single responsibility by delegating additional work to a dependency defined as a simple protocol ("interface") in its constructor, which is useful for readability and modularity (you can inject anything you want, provided it implements the protocol),

The client class has more then one responsibility. It has to log something AND manage dependencies. That's two responsibilities. You can argue for the interpretation of responsbilities, but think about it like this. Compared with a stateless function that doesn't MANAGE ANY STATE, a stateless function is even more "single" in terms of responsibility.

I'm going to stop responding to this thread here. Most of the points are in the other thread, pointless to have two. Just go back to the other thread, state your points, and I will respond.

deltaonefour··on The Composition over Inheritance Principle (2020)
Bro, you're the one being uncivil. Don't make me laugh. I may be arrogant. But being arrogant isn't uncivil. When you insult people and try to "trigger" them that's what's uncivil.

Also that guy I responded to, wasn't asking for clarification. He was dismissing my comment without reading it.

deltaonefour··on The Composition over Inheritance Principle (2020)
>Not quite the same thing. If we suddenly want a file instead of a socket, we need to replace all instances of "socket" in all 1000 files with "file", while LogManager stays LogManager no matter what the internal implementation is - I don't have to modify a single file. Your code isn't flexible when it comes to refactoring. And it's not a synthetic example - we've had real cases like that in real projects.

The only problem with my code and I mentioned it before is that annoying extra variable. To solve your refactoring problem you write an interface to a single class then implement that class how you like.

To solve my problem you write an Interface to both the Function and the dependency. That's it. Same problem as I stated above with the annoying extra variable.

Let me illustrate:

    FunctionType: (d: DependencyInterface, s: str) -> void  //This is defining a type alias similar to interfaces for classes but this is for functions. 

    logFile(d: FileImplimentation, s: str): FunctionType = ...
    logSocket(d: SocketImplementation, s: str): FunctionType = ...

    generalLogFunction(d, s): FunctionType = <logFile or logSocket>


    doStuff(d: DependencyInterface){
        ...
        generalLogFunction(d, "hello world")
        ...
    }
Now if you want to change generalLogFunction just create a new implementation to the function type signature and the dependency interface. Same thing has to be done for the class version of the interface

My example is ALSO real world. Many variables that are externally managed are passed around and function signatures take type these parameters as interface parameters. Golang is an popular example with their CTX that they pass all over the place.

>In this example, you're basically reinventing OOP with structs, just without the syntax sugar, such as polymorphic functions.

No. The delta between OOP and other forms of programming is that OOP scopes methods and data together. There isn't an instance where I do that. Sure you can call it syntactic sugar in the sense that python is syntactic sugar for assembly language, It's all turing complete anyway.

>Usually in real code it's not "the entire class", but an interface.

I am aware of what an interface is. In real code an interface doesn't actually exist. It's just type checking guidelines. The actual data moving around in real code is instances of instances of these interfaces.

>Your SocketWrapper is indeed an example of passing an entire class around.

So? You want me to generalize it? It's an example. Generalizing it doesn't prove my point.

>Readability is also lacking: "Logger" tells exactly what it does: "I can log". If I see SocketWrapper or WrappedSocket, it's not immediately clear what "wrapping a socket" means.

It's just an example. LoggerSocket is equivalent to WrappedSocket. That's the point I'm getting across, they are the same concept. But it Looks like you wanted to talk in terms of interfaces. Well I explained how that works in this comment.

> And your example passes the logger as a function argument - that's not how properly designed object-oriented code works -

There is no properly designed OOP code. Everyone has opinions, you come from the enterprise sector where you guys take certain design patterns from people like Martin Fowler as axiomatic. No man... that's just one flavor of programming, EVEN from the OOP perspective. There are other flavors... see Alan Kay.

>you inject your dependency in the constructor of your class as part of the dependency tree which is initialized somewhere once.

Doesn't this change the signature of the class and therefore break the interface? Well if you make the constructor of the class accept an Interface for a dependency, well then problem solved. But isn't that exactly how I solved it with my function example above? Boom.

>See my argument above that mentioning "socket" everywhere isn't as flexible when it comes to refactoring.

I already countered this point above. For functions you can solve this problem by using an interface for the dependency. If the dependency must be injected anyway then it must be in itself an interface to the interface. If you don't do dependency injection well, this is the only advantage OOP has which I conceded to in my first post: No annoying extra variable. But the Refactoring problem is effectively identical.

>A socket instance can be injected in the logger's constructor and shared by other classes as well, I'm not sure why you think OOP is less modular in this regard.

Again, Doesn't that break the interface?

A logger is a bad example for where OOP breaks down actually because all log functions are IO based and return void so they can't be composed anyway. A better example is this:

  class IntegerAdditionOperations:
     int i = ..
     void add(x: int){i += x}
     void minus(x: int){i -= x}
     ...

  class IntegerMultOperations: ...
     int i;
     void mult(x: int)
How would I create a class using ONLY the primitives above to add 5 minus 6 and multiple by 10 with a member variable? Kind of hard to compose these things.

With stateless functions it's trivial.

   add(x, y)
   sub(x, y)
   mult(x, y)
   add5minus6andMult10(x) = mult(sub(add(x, 5), 6), 10)
deltaonefour··on The Composition over Inheritance Principle (2020)
Where? I need you to spell out the line for me where I used the same symbol twice, because I don't see it. The post is well past the time limit for editing; so whatever it is you're talking about it's there forever.

I also likely have dozens of errors in my psuedocode.

If my arrogance pisses you off you should just take me down by proving my point completely and utterly wrong.

The problem is, you can't. So you resort to being rude and pointing out trivial errors in the code. I'm pretty sure you don't have any argument here.

deltaonefour··on The Composition over Inheritance Principle (2020)
People interpreted my initial reply as arrogance. While it is a bit arrogant, there's a reason for the condescension. Because your flippant reply, implied you didn't even read the code. Any programmer can OBVIOUSLY read the code. You didn't and claimed you didn't UNDERSTAND it. Well here now, you have a full retort and explanation... so were you lying when you said you didn't understand it? Obviously you were. So my equally flippant response was appropriate.

But let's get that out of the way. I appreciate your second reply here.

>In your example, logFilteredWithDateToFile accepts a file. That means, if a function wants to log an error, it needs to accept a file somewhere to pass to the log function (for example, we want the sockets/files to be opened once and be shared across several calls).

This is the intention of how the library works. It actually does promote the sharing of files and sockets. See trivial example below:

    s = WrappedSocket(...)
    logStringToSocket(s, "hello")
    logStringToSocket(s, "world")
See. Socket is shared across several calls. The only thing that's a bit of the eyesore is that extra socket being passed around. But this is a problem that can't be gotten rid of. You either pass the socket all over your code or in the OOP example you pass an instance of a logging class around.

The only benefit of OOP is that the logging class manages the lifetime of the socket. If calls socket.close() for you during destruction. That's it.

>So if function A depends on function B which depends on function C, then function A will need to explicitly state all the dependencies of B and C in its function signature.

No you don't. This is not mandatory. I expose only parameters that are needed by the user and the API. If I want to give the user the ability to filter I SHOULD expose two string parameters, s: str, match: str. because without it the user can't do anything. But I don't have to, see below:

     logHelloWorldWithDate() = print(appendSuffix("hello world: ", time.date().to_string()))
appendSuffix has two parameters required. But I expose zero parameters.

>We end up with a very complex function signature of A where we have to list all possible dependencies of every function it makes use of recursively

There's no recursion going on in my example and none of the logging functions manage any state. Again the function signature is as complex as you want it to be. If there are OTHER required parameters like "socket" and you want to reduce the complexity of the parameters coming in, you can wrap say a socket and a file in a single struct. Not a huge deal either way... Often this variable is called ctx or context, you see it in languages that tend to be more against OOP like golang.

For C++ you can have state managers. Often this exists in the form of things like ThreadPool or **Manager objects. These manager objects are more of a necessary evil though because they lack the huge compositional ability of my example due to the fact that they unionize state and function into a single primitive. Managers overall segregate state away from the rest of your program such that you can have huge compositional ability in the rest of your program as shown in the example above.

>As a client, all I wanted was to ask a function to do one simple thing but now I have to manage files, sockets and god knows what else just because somewhere deep inside someone uses them.

Yes as a client you do need to manage this. I mentioned this problem with the lifetime of socket or file. From the perspective of say a programmer who uses garbage collection it's the same amount of crap being passed around.

   s1= socket()
   s2=socket()

   logWithSocket(s1, "hello")
   logWithSocket(s2, "world")
versus the oop version

   l1 = LoggerThatOwnsASocket()
   l2 = LoggerThatOwnsASocket()
   
   l1.log("hello")
   l2.log("world")
Either you're passing a socket everywhere or your passing the log manager everywhere. If you want something that logs to both socket and a file (multiple dependencies) simple package both of those dependencies in a single struct. This struct can be used for both the OOP version and the non-OOP version. So from the perspective of a programmer who uses garbage collection, the problem presented by both examples here is the SAME, but the 1st example is superior because it is MORE composable and modular.

>As a client, all I wanted was to ask a function to do one simple thing but now I have to manage files, sockets and god knows what else just because somewhere deep inside someone uses them.

Either you're managing a bunch of LogManagers with all the dependencies, Or you're managing a struct with all the dependencies. The problem is the SAME.

>And then in a new version we decide we don't want to log to a file, we want to use a third-party library. Now we need to change signatures of A, B and C, and modify our code at every call site.

Explain this problem with an example. It's too vague. What is the nature of the third party library, what is it replacing?

>Is this what you are proposing?

I've hit all your points pretty thoroughly sentence by sentence. The only thing I haven't resolved is the third-party library thing. Feel free to explain that part and also offer counter arguments to my arguments.

deltaonefour··on The Composition over Inheritance Principle (2020)
>If this is written in the library, that is 2^n combinations of file output functions

This is a feature you want. When you code you want to build things in a style that's modular like legos such that you have the ABILITY to build 2^N or more combinations. Any style of coding that restricts this ability is a detriment. Don't get confused, we're talking about the term "modularity" here. Modularity is a feature you want. Who wants a library/framework/programming language that DOESN'T give them ability to be modular or have the capability of building 2^N combinations? It's about ability not actuality.

Not every high level function needs to be implemented. Like any framework you should be given the tools to build whatever you want. If you want somewthing simpler, that's ok too. Then you wouldn't expose all the core low level functions of the library. You would expose higher level functions in your api and make the primitives private. But to build those high level functions, the way to go is to modularly construct them as I did in the example above.

Maybe they don't need logFilterWithSuffixToFileAndSocket. Then don't create it. You just need the foundational primitives such that if I wanted to create it, I CAN. And you can also expose primitive functions through the API such that users CAN too. That is the core philosophy of programming.

← PreviousPage 2 of 30Next →