Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

OOP does not disallow instantiation with unimplemented functions, it's just an artefact of implementation in some languages.


OOP only disallows inheritance with unimplemented functions when it's a contract violation.

So that is to say, if the base class has a certain function which must be implemented and must provide certain behaviors, then the derived class must implement that function and provide all those behaviors.

The POSIX functions like read and write do not have a contract which says that all implementations of them must successfully transfer data. Being unimplemented (e.g returning -1 with errno EOPNOTSUPP or whatever) is allowed in the contract.

OOP just wants a derived thing to obey the contract of the abtraction it is inheriting, so if you want certain liberties, you have to push them into the contract.


I would call returning something being implemented as a stub rather than being unimplemented. When something is unimplemented and you try to call it, you crash due to a NULL/invalid pointer dereference, not get an error back. Of course, as far as getting things done is concerned, the two might as well be the same, but as far as how the language works, the two are different.


That's just it; in the POSIX world, the library functions like read and write are just a facade. They call something in a kernel, and that something examines the file descriptor and dispatches a lower level function. It's possible that that is literally unimplemented: as in a null function pointer in some structure. The facade converts that to a -1 return with an approprriate `errno` like EOPNOTSUPP (operation not supported).


Crashing is optional, depending on error model of the language. C has pitiful error model, thus you'll usually end up jumping to 0... but I recall at least one C environment where that gave you an error back instead of crash.

As far as OOP is concerned, lack of implementation is not an issue in instantiating something - an object will just not understand the message, possibly catastrophically.


I was referring to POSIX functions when talking about stubs versus unimplemented functions. Messaging in a programming language is a different animal; one that I have yet to fully understand. Objective C for example resolves messages to function calls, so they look like function calls to me. I would love to know how they differ, but I have never dug into it.


Semantically, most OOP models[1] (even C++) involve "messages" that are "sent" to an object. "Methods" are "how do I handle this kind of message".

This usually resolves to a function call because it's the easiest and most sensible way to do it.

Objective-C is more explicit about it due to Smalltalk heritage. Some languages model objects as functions (closures) that one calls with the "message" (an old trick in various FP languages is to implement a trivial object system with closures for local state).

[1] Arguably CLOS with Generic Functions can be seen as outlier, because the operation becomes centerpiece, not the object.


Having a stub or having a NULL pointer are two ways to leave something unimplemented. Which you use is an implementation detail. You can also use some other sigil instead of NULL.


A stub is an empty implementation. An empty implementation is different from no implementation, where there is no code to execute. It is the difference between writing 0 and writing nothing.


If you care about this distinction, yes. However the LWN post describes how both can be used to implement the same behaviour, that their is no defined special implementation.


I have no idea what LWN post you mean. You can make stubs trap by doing a NULL function pointer dereference, but that does not make NULL function pointer dereferences the same as stubs in general.


The LWN post the linked article is a comment to? I thought that's what we are discussing here? There are several paragraphs about exactly this issue.


That sounds like a case of the Liskov substitution principle.


Yes it is, but the point is that without the contract being defined, we can't apply the principle; the details of the interface contract determine what it means to be substitutable.

The LSP is never absolute in a practical system. Because why would you have, say, in a casee of inheritance, a Y which is an new kind of X, if all it did was substitute for X, and behave exactly the same way? Just use X and don't create Y; why create a substitute that is perfectly identical.

If there is a reason to introduce a new type Y which can be used where X is currently used, then it means they are not substitutable. The new situations need a Y and not X, and some situations don't need a Y and stay with X.

In a graphics program, an ellipse and rectangle are substitutable in that they have a draw() method and others, so that they plug into the framework.

But they are not substitutable in the user's design; where the user needs an ellipse, a rectangle won't do, and vice versa.

In that case the contract only cares about the mechanics of the program: making multiple shapes available in a uniform way, with a program organization that makes it easy to code a new shape.

The substitution principle serves the program organization, and not much more.

So with the above discussion in place, we can make an analogy: an ellipse object in a vector graphics program can easily be regarded as a version of a rectangle with unimplemented corners.

The user not onnly doesn't mind that the corners are not implemented, but doesn't want them because they wouldn't make sense.

In the same way, it doesn't make sense to have lseek() on a pipe, or accept() on TTY descriptor or write() on a file which is read only to the caller, etc.


> if all it did was substitute for X, and behave exactly the same way?

LSP is about behaviour existing in the supertype. Adding behaviour doesn't violate LSP.

> In a graphics program, an ellipse and rectangle are substitutable in that they have a draw() method and others, so that they plug into the framework.

The behaviour in question means it draws something. It can draw something different every time, and not violate LSP here.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: