if it's a function, what are the inputs/outputs? do you mean that in the way of "an object is a poor person's closure"?
in case anyone's unfamiliar, here's one basic way to emulate objects with closures. i think i saw it in SICP (?), reproducing it here because i just love how simple it is:
// might be easier to first look at
// the usage example at the bottom
let Point = (x, y) => {
let self = (message, args=null) => {
switch (message) {
// getters
case 'x': return x;
case 'y': return y;
// some operations
// (immutable, but that's not required)
case 'toString':
return `Point(x=${x}, y=${y})`;
case 'move':
let [dx, dy] = args;
// use our getters
return Point(self('x')+dx, self('y')+dy);
// let's get DRY!
case 'plus':
let [other] = args;
return self('move', other('x'), other('y'));
default:
throw Error(`unknown message: ${message} ${JSON.stringify(args)}`);
}
};
return self;
};
let p1 = Point(3, 5);
// sending messages
p1('x') === 3;
p1('y') === 5;
p1('move', [1, 2])('toString');
// --> "Point(x=4, y=7)"
let p2 = Point(1, 2);
p1('plus', [p2])('toString');
// --> "Point(x=4, y=7)"
dynamic dispatch & message passing, just like that! and you can easily do `__getattr__/method_missing`-style dynamicism just by looking at `message`.
for the other way around, see how Java lambdas desugar to objects with a "call" method and closed-over variables as members.
i intended to put "(and vice versa)" in a footnote, but forgot about it! you can see a relic of that in the last paragraph.
though i must say, i'm pretty happy in languages that have closures but don't have objects, as long as there's a nice way to do ad-hoc polymorphism (like traits/typeclasses)
also, i just made a possibly interesting connection with JS methods (and their weirdness). in the above implementation, a message is first class, so you can send the same message to multiple objects:
let moveUp = ['move', [0, 1]];
p1(...moveUp)
p2(...moveUp)
but you can't get a `move` that's "bound" to a particular object¹ – the "receiver" is decided when you "send" the message. which reminds me of how JS methods work: `this` is bound to what's "to the left of the dot" when you call a method, so unlike Python,
obj.foo(1)
is not the same as
let f = obj.foo
f(1) // Error: 'this' is undefined
maybe there's a connection to some language that inspired JS' OO model, with prototypes and all that?
---
¹ well, unless you explicitly wrap it in another closure like
But that's essentially a table lookup, not a vtable lookup, right?
Dynamic dispatch implies that you dispatch based on the class of the receiver. For instance, you can't have a Point3 value that uses Point's implementation of 'x' and its own implementation of 'toString' under this example.
maybe "extremely late binding" would be more appropriate? it's true that usually "dynamic dispatch" means a vtable, but i think this is dynamic dispatch in spirit - in fact "dispatching" messages to implementations is pretty much the only thing a closure-object does :) i chose to write the impls inline, so they're p much impossible to reuse, but that's not required.
> you can't have a Point3 value that uses Point's implementation of 'x' and its own implementation of 'toString' under this example.
you can't do much of anything under this this example! i didn't think a whole object system would fit in a HN comment, i intended it to be minimal :)
this is particularly visible in the implementation of `plus` – `other` might not be a Point at all, so `other('x')` and `other('y')` might do anything; which i'd say is textbook (ad-hoc) polymorphism.
i remember reading this somewhere: "branching on values is the ultimate dynamic dispatch" :)
thank you :) i hope i didn't hijack the thread! but i just love sharing stuff like this
> the set of all public methods could be seen as 1, but not the only, interpretation of the functional interface.
could you describe another interpretation? "the set of public methods"¹ is the only thing i can think of when i hear about an object's "functional interface". it could be a terminology issue though – i'm reading "functional interface" in a general sort of way, but i could imagine it having some specific definition in OO theory.
---
¹ or recognized messages, in a more smalltalk-ish context
The other interpretation has slipped my mind since yesterday, sorry mate. I do think it's an interesting idea that I now see I have no formal understanding of. Cheers.
PS. if you're interested in weird perspectives on this, you might find Coinduction (and "codata") interesting. from wikipedia:
> Informally, rather than defining a function by pattern-matching on each of the inductive constructors, one defines each of the "destructors" or "observers" over the function result.
it's a deep rabbit hole, but i remember it being applied OOP-ish things – "destructors" would roughly correspond to exposed methods.
in case anyone's unfamiliar, here's one basic way to emulate objects with closures. i think i saw it in SICP (?), reproducing it here because i just love how simple it is:
dynamic dispatch & message passing, just like that! and you can easily do `__getattr__/method_missing`-style dynamicism just by looking at `message`.for the other way around, see how Java lambdas desugar to objects with a "call" method and closed-over variables as members.