Live data from Hacker News

When objects are not enough (2021)

tonysm.com

11–20 of 58 posts

Re: When objects are not enough (2021)

#11
post #6

Earlier quoted context omitted.

It's not a requirement, but an immutable object has fewer uses than a mutable one. Functions/methods/actions/operations are just different names for the operations which mutate the state of the object. So, I would argue that they are a necessary attribute of mutable objects.

We could say that mutability (or having functions/methods/etc) is part of the object’s identity.

I consider identity to be an object that is exclusively itself, and knows what it is. You can treat it in an opaque manner, and its own identity will dictate how external stimulus works on it.

Re: When objects are not enough (2021)

#12
post #6

Earlier quoted context omitted.

It's not a requirement, but an immutable object has fewer uses than a mutable one. Functions/methods/actions/operations are just different names for the operations which mutate the state of the object. So, I would argue that they are a necessary attribute of mutable objects.

Maybe, but mutability does not require inbuilt operations. I have often used data-only objects, and passed them to fixed-context functions. It's a cheap way to get OO behavior, in non-OO languages.

I would still classify that as object oriented behavior.

You have a class/type of objects, and you have a set of functions or operations which are associated with (loosely or tightly) and operate on that type of object.

For example, I would say that file descriptors are a handle to a type of object. They encapsulate the thing that they represent (file, DRM buffer, eventfd, whatever), and some of the functions that operate on them are polymorphic. For example, read, close, ioctl, etc., don't care if the file descriptor is a file, a queue, or whatever.

You use syscalls to interact with file descriptors, but they are just as much object handles.

Re: When objects are not enough (2021)

#13
+1 for use of the word "Reification"!

There's another universe of object-adjacent systems that may or may not be connected with conventional OO programming languages. Two examples I'd point to are Microsoft's COM (designed so it is straightforward to write and call COM objects from C) and the "objects" in IBM's OS/400. In both of those cases I think the reification is the important thing, although you can see reification in Java's object headers where objects get a number of attributes necessary for garbage collection, concurrency control, etc.

Re: When objects are not enough (2021)

#14
post #12

Earlier quoted context omitted.

Maybe, but mutability does not require inbuilt operations. I have often used data-only objects, and passed them to fixed-context functions. It's a cheap way to get OO behavior, in non-OO languages.

I would still classify that as object oriented behavior. You have a class/type of objects, and you have a set of functions or operations which are associated with (loosely or tightly) and operate on that type of object. For example, I would say that file descriptors are a handle to a type of object. They encapsulate the thing that they represent (file, DRM buffer, eventfd, whatever), and some of the functions that op…

It definitely is. I was just talking about the definition of "an object."

It separates the functionality from the object. Turns it into an external stimulus to change the state of an object.

I used this pattern, back in the 1990s, to make a C API behave like a C++ API. This was back when every compiler had a different stack convention, and the only one we could rely on, was C.

To be fair, I did have function pointers, in some of the objects, that acted as "poor man's vtables."

I know that the API was still in use, 25 years later.

Re: When objects are not enough (2021)

#15
The objects are just one tool. You usually need a few to do the job well.

The biggest thing I've seen blow up actual OOP projects has been a lack of respect for circular dependencies in the underlying domain. If you have one of those problems where it is ambiguous which type "owns" another type, then the moment you start writing methods in these types you are treading into the dark forest. Often times it is unclear that your problem exhibits circular dependencies until code is already being written and shipped.

My approach to these situations is to start with a relational data model. A SQL schema (and its representative DTOs) can model circular dependencies competently. You can then have additional object models (views) that can be populated by the same relational data store (just a different query). One other advantage with the relational modeling approach is that it is very easy to explain things to the business before you write a single line of code [0]. The purpose of a SQL table can be demonstrated with a sample excel sheet with mock business data.

This path was largely inspired by Out of the Tar Pit [1] and practical experience in fairly wicked domains (semiconductor mfg., banking, etc). I am not sure Functional Relational Programming is the answer for everything, but the "Relational" part certainly seems to be universally applicable.

[0]: https://en.wikiquote.org/wiki/Fred_Brooks#:~:text=Show%20me%....

[1]: https://curtclifton.net/papers/MoseleyMarks06a.pdf

Re: When objects are not enough (2021)

#16
post #6

Earlier quoted context omitted.

It's not a requirement, but an immutable object has fewer uses than a mutable one. Functions/methods/actions/operations are just different names for the operations which mutate the state of the object. So, I would argue that they are a necessary attribute of mutable objects.

Maybe, but mutability does not require inbuilt operations. I have often used data-only objects, and passed them to fixed-context functions. It's a cheap way to get OO behavior, in non-OO languages.

Yeah, object orientation isn't just a language feature, it's a pattern for structuring interaction with data.

And as for object orientation being less useful in immutable languages, I see it used plenty.

Erlang and haskell both define dictionary types that return new copies of the dictionary on what would normally be mutating function calls. The dictionary's gory details are hidden behind the object's mask, leaving the user free to ignore if it is a hash into an array of arrays, as many dicts used to be and as allows sharing most of the entries between copies of the dict until resizing, or maybe it's actually a balanced tree or just an a-list.

The outer code doesn't need to know because you create and manipulate the dictionary abstractly through helper functions, be they attached via the language or simply exposed while leaving the implementation opaque.

Object orientation will also be used to hide the implementations of files, sockets, and other abstract resources.

Many interfaces throughout the linux kernel use a plain C form of object orientation, a language which is definitely not object oriented on its own, filling out an 'interface' structure with functions to be used for objects originating from a particular area, allowing the kernel to interact abstractly with filesystems via the function pointers in the struct, for example.

Re: When objects are not enough (2021)

#17
post #12

Earlier quoted context omitted.

I would still classify that as object oriented behavior. You have a class/type of objects, and you have a set of functions or operations which are associated with (loosely or tightly) and operate on that type of object. For example, I would say that file descriptors are a handle to a type of object. They encapsulate the thing that they represent (file, DRM buffer, eventfd, whatever), and some of the functions that op…

It definitely is. I was just talking about the definition of "an object." It separates the functionality from the object. Turns it into an external stimulus to change the state of an object. I used this pattern, back in the 1990s, to make a C API behave like a C++ API. This was back when every compiler had a different stack convention, and the only one we could rely on, was C. To be fair, I did have function pointers…

It's possible that we are talking at cross purposes.

I think you might be arguing that the object itself does not include the set of functions/methods/operations that act on it, whereas I see them as another attribute of the class/type which is an attribute of the object.

Re: When objects are not enough (2021)

#18
post #6

> An object has state and operations combined. My own definition has always been that an object has state and identity . I have never considered functions/methods to be a requirement for something to be an object.

It's not a requirement, but an immutable object has fewer uses than a mutable one. Functions/methods/actions/operations are just different names for the operations which mutate the state of the object. So, I would argue that they are a necessary attribute of mutable objects.

OOP schemes like CLOS, Dylan, S4, and others keep Objects and Actions separate. This is similar to Haskell type classes.

Re: When objects are not enough (2021)

#19
I want to re-read this and think about it more.

But one thing stuck out: I never liked most of the distillation of actions as clean architecture would advocate for, be they lambdas in class form (DepositAction) or interactors. I feel strongly that they are the right thing in describing business logic, however.

What did click for me is the conceit of a service, which the JVM world embraces. Services are plain old objects that have a method for each action you'd like to model. This is nicer than the aforementioned approaches because there is often common code to different actions. Like actions, services are the place where validation happens, persistence happens, and all of the interesting business logic. IO and orthogonal concerns are injected into them (via constructor), which lets you write tests about the core logic pretty easily.

What you get is the ability to reason about what happens without the incidental complexity of the web. Web handlers then boil down to decoding input, passing it to the service, examining the result of calling an action, and then outputting the appropriate data.

That's all they should've ever been doing. :)

Re: When objects are not enough (2021)

#20
post #6

> An object has state and operations combined. My own definition has always been that an object has state and identity . I have never considered functions/methods to be a requirement for something to be an object.

It's not a requirement, but an immutable object has fewer uses than a mutable one. Functions/methods/actions/operations are just different names for the operations which mutate the state of the object. So, I would argue that they are a necessary attribute of mutable objects.

Object identity effectively implies mutability. Without that implication, two objects of the same structured value being non-equal doesn’t mean anything (and would probably be better classified as a mistake).

Another way to look at it is that property setters (or whatever mechanism is used to directly mutate an object’s sub-data) is not meaningfully different from a method doing the same. You could even call it syntax sugar for the same.

Post reply on HN