12 ms·
None of these situations require an object to do. You can always have a function that takes in an extra ‘state’ argument. You can then do everything you said by
by amw-zero 6y ago
None of these situations require an object to do. You can always have a function that takes in an extra ‘state’ argument. You can then do everything you said by passing in the corresponding state values.
- rocho 6y agoPrecisely. And that's the way it's done in functional languages.
- millstone 6y agoNo, it's done inverted in functional languages! In a FPL your graph will be an ADT. The advantage is clients can pick it apart, but there is no easy way to extend it. If you wanted to "use the same object for computing distances to multiple vertices", you're screwed: the ADT is laid bare, and there is no data hiding. In an OO language, your graph will be an opaque object, and you can write things like CachingDijkstra or ParallelDijkstra and make these work transparently for your clients. The price is that you are bound to your APIs: a client cannot pick apart your data structure, because it's opaque.
- danielscrubs 6y agoWe do have data hiding in functional programming, even if we would not have modules, which we do, we do have type classes, and for example in OCaml you can hide constructors if that's your jam. It's not like when I use a sorting function that the implementors couldn't swap it out for a caching one or a parallel one. One of the amazing things I remember is changing an int to a float in a very well used "struct" that was touching thousands of functions but because the functions in Haskell usually so extremely general I didn't have to change a single other line (Number type is heavily used and doesn't incur an extra performance cost, which it very much does in Java). In fact we can be even more precise or loose in what assumptions need to be made via dependent types in functional programming languages like Agda. I encourage you to take a look at any popular Haskell-framework to see how it's done in practice.
- taejo 6y agoThe A in ADT can stand for both abstract and algebraic, so it's an unhelpful abbreviation in contexts where both algebraic and abstract datatypes are relevant. Functional programming languages tend to have good support for algebraic types (which I think you mean) but they can often do data-hiding too! In Haskell, for example, you do this by not exporting the data constructors for your type, so they can only be used within the module that defines the type.
- bo1024 6y agoI think using existential types will give you data-hiding like this. (Disclaimer: I'm still learning about them, and making up this syntax.) Say my abstract data type is DijkstraLib = there exists GraphState with { construct: List(Edge) -> GraphState getDist: GraphState -> Vertex -> Vertex -> Num } Now we can write two different implementations of this type that use a different data structure for graph. The data structure will be opaque to the client (even though the client obtains and passes around graph objects!). Like so: -- Library type CachingDijkstraLib : DijkstraLib with GraphState = (HashMap((Vertex, Vertex), Num), List(Edge)) with { construct(a_list) = (HashMap.empty, a_list) ... } -- Client DL = CachingDijkstraLib : DijkstraLib some_obj = DL.construct(edge_list) DL.getDist(some_obj, u, v) DL2 = SomeOtherDijkstraLib : DijkstraLib some_other_obj = DL2.construct(edge_list) DL2.getDist(some_other_obj, u, v) The types of some_obj and some_other_obj could be completely different, and neither would be accessible to the client. For example, the client couldn't assume some_obj is a pair and try to get its first element. It would also be an error to call e.g. DL2.getDist(some_obj, ...).
- cataphract 6y agoBut if you're passing a state object around, you might as well use a class, no? Admittedly simplifying a bit, an instance method is a function that implicitly takes "this" as the first argument.
- amw-zero 6y agoWhy? You would never suggest this if OO wasn’t the predominant paradigm. What is the benefit of implicitly passing the parameter? I prefer to see it passed explicitly, so the implicit passing is a downside to me, not a benefit.
- hamandcheese 6y agoThe benefit is encapsulation.
- _0ffh 6y agoDon't need a dedicated OOP lang for that benefit. It's an age-old discussion. As old school software engineering became sufficiently advanced, some people bundled their favorite "state of the art" concepts, and called it OOP. (Also: Multiple people, multiple different concepts of what "OOP" actually precisely means.) It became a horrible hype, and from then on out everyone was taught to see all these concepts as "OOP concepts" that elevate OOP over other programming paradigms. But they're not and they don't. The only real "advantage" is, OOP languages are opinionated and will try to force their interpretation of these concepts on the coder. Which is nice, if you happen to like it that way. Just not everybody does.
- fnord123 6y agoEncapsulation's a weird one. It's a cornerstone of OO but most/all OO languages have rubbish support for ABIs so changing your object in one library means you need to recompile your code using the library. This is the opposite situation that encapsulation seems to promise (in my view).
- thom 6y agoIs encapsulation different in either case? Nobody should be operating directly on the state, any more than they should be reflecting on private fields in a class.
- edflsafoiewq 6y agoYou're talking about s.f(x) vs f(s,x)?
- endgame 6y agoCan't you close over the state, so the library doesn't need to see and pass around the extra parameters?
- Barrin92 6y agoIf you're at the point where you'd rather pass a state argument around rather than use an object you've thrown out OO categorically and there's no point to even discuss anything. The article in question talks about when it makes sense to use functions within the OO paradigm instead of classes. Generally using classes when modelling persistent state is not an anti-pattern, because that's what classes are for.
- layoutIfNeeded 6y agoCool idea! Actually, you could probably call this extra argument "this".
- loopz 6y agovoid do(withThis, that) { that(withThis) } Why be implicit with anything, when you can provide nice headscratchers for the next clown! ;-) Seriosuly though, most OO-languages brings not much to the table other than being "OO-centric" (methods+data vs procedures|functions). OO without encapsulation of data and implementation though, may even be worse abuse than no OO. So one can by convention even do OO without direct support for it in the language itself, by using any form of indirection that encapsulates data and implementation. REST typically fails this, because it often exposes direct access to internal resources (CRUD).
- JoeAltmaier 6y agoSure, you can build your own object and pass the 'this' pointer around manually. You could use C for everything, and tediously do everything again that objects do for free. But why? There's a lot of object-hating going around. Its silly. Use objects to encapsulate functionality, they are good at that and everybody understands what it means.
- tempodox 6y agoWhat you call “for free”, I call implicit. Passing it as function arguments makes it explicit. You don't need to “hate” “objects” to prefer the explicit over the implicit.
- JoeAltmaier 6y agoExcept for the title of the OP, which seems argumentative. The context pointer for an encapsulated set of functionality, need not be passed around. It adds little or nothing. In a language full of encapsulated functionality, it stands out like Chekov's Gun. I'd argue, there better be a damn good reason to deviate for normal practice. And not just 'I prefer the explicit'.
- quietbritishjim 6y agoI think you could apply your argument to any use of objects, unless there are virtual methods involved. So you probably would have to be pretty generally against the use of objects to agree.
- tempodox 6y agoClasses for use with stack-allocated instances in C++ are also very handy. Makes it easy to control the extent (i.e. lifetime) of the side-effects they produce.
- nitrogen 6y agoI don't find all that much of a difference between notations like set.map{...} and map(set){...}, so at that point I suppose it really is just aesthetic preference.
- gbrown 6y agoIsn’t that just axiomatic? Of course anything you can do with a class you can do with a function + state. The prose is to make that pattern more natural for humans to program and use.
- raducu 6y agoBut after a couple of arguments, fields inside an object become more appealing -- this is about taste. But even if you have free functions, as they become more complex, you tend to group them together, so at that point you might just slap the "class" keyword somewhere at the beginning of the file and just call it a class.
- ImprobableTruth 6y ago>But after a couple of arguments, fields inside an object become more appealing -- this is about taste. I don't understand this. The difference between passing a structure implicitly or explicitly will always be a single argument. >But even if you have free functions, as they become more complex, you tend to group them together, so at that point you might just slap the "class" keyword somewhere at the beginning of the file and just call it a class. Sure, but at that point you're not really using any class features. If you're just using classes as modules, why not use modules directly?
- crooked-v 6y agoNothing made this as clear for me as using the Nim language, where functions defined as proc doThing(x: MyObject; value: string) can be called both with doThing(x, y) and with x.doThing(y) where x by itself is 'just' a data object, but is treated transparently by the language as having associated functions, setters, getters, etc as if it were a class (even though they can all also be directly called separately). It's an approach that I find really elegant and that I wish more languages used in some way.
- mehrdadn 6y agoYou certainly can do that. You can also refer to John Smith as "Mr. Smith", even when he's your dad. Whether it's more natural or more jarring or confusing is another question though...
- comfydragon 6y agoThat's a thing you can also do in Python: class MyObject: def doThing(self, value: str) -> None: # whatever pass obj = MyObject() obj.doThing("value!") MyObject.doThing(obj, "a different value!") The only difference is that doThing is namespaced to the MyObject class.
- otabdeveloper4 6y ago> ...a function that takes in an extra ‘state’ argument. That's exactly what a 'class' is.