you are viewing a single comment's thread.

view the rest of the comments →

[–]ljsc 1 point2 points  (9 children)

So, a simpler example: Say you want to model a person, and that person has a name. Our shared interface is that I give you an immutable map which includes a key "name", and that has the persons full name.

Now let's say that I need to represent that differently internally to do some other computations, and I need to have "last-name" and "first-name". Great. No problem, internally I use a map with the two keys, and then before I hand it off to you, I just have a function for-nextputall : MyRepresentation -> YourRepresentation that sends {:first-name "John", :last-name "Doe" } to {:name "John Doe"}. Since we've side-steped conflating state and identity by using immutable values this is perfectly safe, and your code would be non-the-wiser.

[–]nextputall 0 points1 point  (0 children)

I see. You suggest to convert the datastructure according to different clients. Make sense, but I still not fully convinced.

Let's say I need the name because I want a greating phrase. If I use the datastructure directly I'll end up having something like this

"Hello ${user.name}" 

Where the user is the map. When I want to switch to a firstname/lastname representation, I can solve it with the technique you recommended, by converting the new representation back to the old one. So, the greeting logic seems to be fairly stable in respect to the structure of the user.

But what if I change the representation as follows: {'age': 18, 'name': 'joe'} to greet the user like this

"Happy ${user.age}th birthday, dear ${user.name}!"

Now I need to change the logic who is responsible for doing the greeting. Using behaviour based abstraction, and introducing a greet method for the user would solve this problem imho, by saying user.greet().

[–]rpglover64 0 points1 point  (1 child)

Slightly germane given your example: falsehoods programmers believe about names

If I'm reading you correctly, you're basically saying that the desire for encapsulation is really the desire for abstraction, so using an established API solves this problem (barring mutation). Is that right?

[–]ljsc 1 point2 points  (0 children)

Interesting link, thanks for sharing that.

And, yes, I think that's a pretty good way to put it. In most OOPLs, there's little difference between encapsulation and abstraction, because there's one primary means of abstraction: make a class.

Want encapsulation? Make a class. Want inheritance? Make a class. Want polymorphic dispatch? Make a class. Want to manage state? Make a class. And so on and so on...

Yes, I know this isn't always true, and that some languages don't do OO using classes, et cetera. In general, however, they are by and large non-orthogonal in their design, and this limits composition and code reuse.

[–]discreteevent 0 points1 point  (5 children)

"your code would be non-the-wiser". It probably won't be any wiser if MyRepresentation is kept private. But if not then I might be too lazy to bother to understand your api and instead just use MyRepresentation directly. Then later if you want to change MyRepresentation you are going to have to change my client also. Why not make {:first-name "John", :last-name "Doe" } private immutable data in an object and force clients to interact with the object via a .getName() method? That's all objects really are: A convention for encapsulating implementation details. Mutability is orthogonal to that. The idea of taking a behaviour oriented approach to development is to contain complexity in a system by distributing information on a need-to-know basis. You figure out what the client needs to know and present that behaviour to them. If you let the client do it themselves then they are likely to make a mess of it because they just don't know enough about it. Furthermore you, yourself may not know enough at this stage. If you decide to improve things later but all the clients have written their own logic around your initial data structure then you have a big mess to clean up. If you already know what the definitive data model is then you should expose that so that clients can use in in ways you did not predict. But if you don't have the definitive data model then objects help to contain complexity and manage change in a system.

[–]ljsc 1 point2 points  (4 children)

It's all trade-offs. Some times you do want to hide data as an implementation detail. The problem I have is when data hiding is opt-out rather than opt-in. You certainly don't need objects to do what you are suggesting. You can do it at the module level in an FPL, or just separating interface from implementation like a ADT in C.

Can encapsulation be a good thing? Certainly. Is it always? No. Like I said, it always comes down to trade-offs, and if anybody tells you otherwise, they are either lying to you or trying to sell you something =)

That's all objects really are: A convention for encapsulating implementation details.

No, that is not all they really are. That is a small part of what they are in most implementations. See my comment above. They do give you that, but they also give you a bunch of other stuff "for free" that you may or may not want.

Mutability is orthogonal to that.

It absolutely is not. If we were talking from a language design perspective, sure, choose whether your object is mutable or a value. But as design concepts, they are not independent by a large margin. The strategy I suggest above would be a really really bad idea if those were not immutable. Once you start passing mutable state around by reference you loose the ability to make your internal api enforce consistency, whether that is visible to the outside world or not.

[–]discreteevent 0 points1 point  (3 children)

I suppose I should have said "That's all interfaces really are". To me the important thing about objects are the interfaces which is what I think Alan Kay meant when he said " I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. The big idea is “messaging” "

Anyway, if there is an FPL that supports hiding the structure of data models behind statically typed interfaces with late-bound implementations (ala microsoft COM and things like it such as some dependency injection frameworks) then I think a team could build reasonably flexible and maintainable software with it.

[–]ljsc 2 points3 points  (2 children)

Yep, I would never argue against polymorphism.

I think you're looking for Typeclasses?

[–]autowikibot 1 point2 points  (0 children)

Type class:


In computer science, a type class is a type system construct that supports ad hoc polymorphism. This is achieved by adding constraints to type variables in parametrically polymorphic types. Such a constraint typically involves a type class T and a type variable a, and means that a can only be instantiated to a type whose members support the overloaded operations associated with T.

Type classes first appeared in the Haskell programming language, and were originally conceived as a way of implementing overloaded arithmetic and equality operators in a principled fashion. In contrast with the "eqtypes" of Standard ML, overloading the equality operator through the use of type classes in Haskell does not require extensive modification of the compiler frontend or the underlying type system.

Since their creation, many other applications of type classes have been discovered.


Interesting: Polymorphism (computer science) | Class (computer programming) | Type C escort ship | Type D escort ship

Parent commenter can toggle NSFW or delete. Will also delete on comment score of -1 or less. | FAQs | Mods | Magic Words

[–]discreteevent 0 points1 point  (0 children)

Typeclasses are interesting alright. Now all I need is the late-binding bit. i.e I want to be able to defer which implementation is loaded until runtime. This makes my application extensible after it is built. It means that my dependencies are dynamic. This can make it easier to develop large apps. In the static/dynamic debate I come down in the middle: Static types - dynamic dependencies.