Does anyone have handy any criticisms of Self-styl...
# thinking-together
i
Does anyone have handy any criticisms of Self-style prototypal inheritance? I'm not interested in performance, just the idea as a mechanism for dynamic data composition that lets you manage duplication vs references. What causes it to fail (eg: become unmanageable), where other kinds of data composition do not? Also accepting links to good summaries of how Pharo handles inheritance/composition.
t
Can you post a quick code sample of self style prototypal inheritance?
w
“composition over inheritance”
g
one thing i find confusing is understanding when state or closures are private to an instance vs its prototype
👍 2
i
@Tyler Adams — Here's a decent summary I came across the other day: http://gameprogrammingpatterns.com/prototype.html#self If you're familiar with JS inheritance, it's similar. Note that in my case, I'm only interested in using prototypes as a form of data composition, not method / function / class composition.
m
Prototypical inheritance seems to me to have the worst of both worlds of dynamic typing and inheritance: fragile base class problem PLUS the ability to change the base class at runtime.
i
Further to my original post, I'd be curious to hear if anyone has come across the idea of field-level inheritance, where each field may be delegated to a field on a different object. Are there any systems that do this well?
@Michael Coblenz Does the fragile bass class apply to data? All the examples I can imagine are due to method inheritance, not data inheritance.
m
How do I know what fields an object has?
In prototype-based languages, the answer seems to be “inspect the object at runtime and see.”
👍 2
But ultimately you need to write code that makes assumptions about what fields are there.
So you run the code once, see that field f is there in the debugger or whatever, assume it’s always there, and then later, BOOM.
👍 2
t
Ah, general inheritance forces a taxonomy of your data which means there's a limited number of options and a unique parent. Which class should I inherit from? Diamond problem "I really want to inherit from both ork and car" With composition, you can get an unlimited number of options and no dependency issues. I can make an ork car, why not! self style is a dynamic typing approach to OO. Fast and lightweight, but no static analysis help.
👍 1
methods or data, it doesn't make a difference, esp in js where methods are first class
e
best to avoid OOP paradigm entirely. Don't ever create or destroy an object and life becomes so much simpler. Then you don't create islands of state but instead have one central ball of state which can be serialized, communicated, etc. OOP creates islands of state that are nearly impossible to transmit across the network in a synchronized manner.
i
Thanks for the replies everyone, but I guess I didn't articulate my inquiry very well. I'm asking very specifically about Self-style prototypal inheritance applied to data, and the idea of field-level delegation in particular. If you have a specific critique about that exact style of inheritance/delegation, that'd be helpful. General critiques of OOP, classes, inheritance, or dynamic typing — especially critiques of the form "these things are just bad, QED" — are outside the scope of my concerns at the moment. I'm especially interested in hearing from folks who have worked with or (especially) built systems that use this style of inheritance, or who have considered using it in the design of a live programming environment but then decided not to. Eg: if @Tudor Girba is still around, it'd be great to hear from him.
w
Done quite a bit with prototypes. Pain points... Don't do great with objects that have complicated life-cycles. Tend to have trouble when collaborating with other objects. When I clone this, should I clone this part? When I clone this, should some list of whatever's now include the clone? You need to think a lot about aliasing, the difference between a clone and a copy, and so on. Prototypes have an advantage in systems that try to make objects tangible, like Self, since physical tokens work in a similar sort of way making for decent transfer.
👍 1
i
@wtaysom Great points. I'm coming at Self prototypes from a weird angle. I've done a lot (a lot — like 5-10k hours in a past life) of 3d modelling across a dozen tools. In those environments you often have fairly rich control over aliasing/instancing vs copying, and it's unambiguous. It was a good experience (eg: the "fragile base" is a powerful tool, not a pain point). Self feels only a small bit more complicated than that, which makes me think that a sufficiently rich GUI would make Self prototypes an equally good experience. ... For data composition. Period. Prototypal code composition, on the other hand, I am not touching. Not unless I can work out some nice af way of visualizing it, which seems unlikely.
e
the beauty of 3D instancing vs copying is that 3D objects are collections of triangles, textures, etc. which are all static in the sense that the component triangles don't affect each other. The more purely you enter the data domain, which is where Spreadsheets excel, the more tangible it gets. In a way the Schema designer of Filemaker Pro is a prototype designer, which has a very nice GUI. I consider Filemaker to be one of the best, if not the best, front end for MySQL around. You are effectively creating a form in which data is poured.
w
Yes, for modeling prototypes seem to work well. The two other ideas I find interesting are parameters and holes. By a parameter, I mean some measurement that can vary likely bound to others, which is a kind of inherence. By a hole, I mean a blank that can be filled in. A parameter is like having a hole filled with a sort of nondeterminist value. And with holes, as you add more and more, you find yourself in a very lambda calculus sort of world. At which point, manner of expressing how to fill holes seems to matter more than the basic, fully realized object. And getting all these notes to harmonize? Well, that's the project.
👍 1
t
@Ivan Reese In our work, we use inheritance, but we favor composition. We use inheritance strictly to model logical subtyping. But, in general, we favor composition out of tiny objects.
Take a look at this visualization showing how a single empty visual element (shown in red) is linked with many tiny non-primitive objects. For example, we have a full object representing only border (depicted in blue) which, in turn, is made of other smaller objects.
We find the composition of explicit objects to be essential. In particular, in a live environment we want to be able to swap things at runtime and we want the views to update accordingly.
We apply this concept at all levels of abstractions. Above we see how even modeling of a single visual element can be split into tiny parts. Now, when we make some of those tiny objects behave like functions, we can get very interesting effects. For example, a common issue in user interface design is to adjust the look of widgets. Often this is set through a global theme. We want to be able to affect the look of a single widget. CSS is an interesting source of inspiration, but when people want to affect the structure of the DOM, they resort to JS. Not quite the most elegant combination. So, we introduced the concept of a look. Any element can get a look injected, and a look can affect everything in the element, including its structure and the way it handles events. The look is an object, but it acts like a transformation. Through object composition we can swap it in and out at runtime. In a way, a look is like a property of a prototype object (in Pharo, these would be called talents, or object traits). We find this to be quite powerful.
👍 1
For example, here is a single label widget. By default, it is only a case that renders nothing and has no children.
But, when we add a look to it, the look adds an actual child that draws the text.
These are some examples that relate to the ui, but we apply these ideas to everything we build.
@Ivan Reese Does this address the question?
i
The system we’re building is very Selfy. Physical, concrete, no inheritance, just copying and powerful group selection/edit. I’m very bullish on where it’s headed. We’ve used a purely textual version to build a bunch of different things across the complexity spectrum and it’s been a breath of fresh air. 🙂 I don’t think it’s quite the right fit for text though. You really do need the concrete editor that Self has. So that’s what we’re working on at the moment.
d
If the goal is just code reuse, then there's no actual need for any inheritance or prototype relation to exist at runtime. This is the philosophy behind "traits", which are like mixins, where the idea is a static composition of code at compile time (note: many languages have a feature called traits or mixins, which are not the same thing because they are implemented using runtime inheritance -- I'm looking at you, Scala!) Here's the actual/original paper: http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf And another that adds fields / properties: http://scg.unibe.ch/archive/papers/Berg07aStatefulTraits.pdf
i
@wtaysom You're right on my wavelength. The thing you call "parameters" goes by a bunch of different names in the various 3d tools I've used, and they are occasionally wonderful to work with, depending on the tool. That sort of field-level inheritance(-ish) is what I'm aiming toward. Really, it's just another form of 1-way data binding, though it really sings (to borrow your metaphor) in a live environment.
@Edward de Jong / Beads Project
the beauty of 3D instancing vs copying is that 3D objects are collections of triangles, textures, etc. which are all static in the sense that the component triangles don't affect each other. The more purely you enter the data domain, which is where Spreadsheets excel, the more tangible it gets.
Yes and no. In 3d, you hop up and down the ladder of abstraction at a blistering rate. Yes, you'll spend a lot of time working at the level of individual verts, edges, tris, faces, but even then, you care immensely about the relationships between them. For instance: if you keep a strip or a ring of faces fairly uniform, it's easy to grab the thing and work with it as a set; by keeping face angles or areas consistent, you create an ad hoc geometric abstraction, and the tools are designed to help you do this and leverage that. When you leave that lower level and start working with surface groups, meshes, objects, rigged collections of objects, etc., you're now working largely with nondestructive procedural modifiers, where tightly-controlled and well-understood relationships (and cross-cutting ones at that) become immensely important. So even though the data is at rest, so to speak, you still need to grapple with abstraction, structure, interdependence, sequence, declaration vs procedure, memory vs computation cost (both of the data and the transformations), and so forth. And then when you start adding animation, physics simulation, particles, etc., your data is no longer at-rest, and changes to your supposedly "static" data like geometry in the small can have rippling consequences in the large. And again, there are enviably rich tools for helping you manage it.
e
Having tried and failed to conquer 3D Studio Max, a product i remember paying $3000 for, 3D products are by far the most complex programs people operate, and i find them very difficult to use. In Maya every operation you did on the screen was represented in their programming language, so it really was a textual command stream that you generated. A very powerful modality, but also quite complex because you are operating in two domains at once. It is true however that 3D products and spreadsheets have lots of data, and the ratio of data to code is often very high. In my Chess program sample that i wrote in Beads, there is almost no data in the game. It's an 8x8 grid with 2 pieces of data per square (side, piece), and a handful of other data about whose turn it is, have the kings moved, etc., and the vast majority of the program is calculating legal moves, and handling the weird things like en passant capture and castling. I have programmed many things where logic dominated and data was very sparse. I found this pattern to be true, the top of the program is all graphical, and the bottom layers are all logic.
i
Max was my fourth or fifth 3d program, and I picked it up in the 8th grade, with no tutelage and almost no references/tutorials. Maya was next, in the 10th. (And then Modo, and then...) They're tools that require a kind of expertise, yes. But the ramp from novice to expert is enviably smooth, such that it can just be a matter of putting in the hours doing self-driven experimentation. In terms of the way you initially explore them, they're more like learning a musical instrument than learning a language (programming or spoken), in that they are almost completely self-revealing or self-discoverable. That's what I'm after with my enthusiasm for live programming. An interested teenager should be able to learn how to program, from novice to intermediate, with just a dev environment and no other references or guidance.
@Tudor Girba Yes! Your comments and screenshots were immensely helpful, thank you. I know so very little about Pharo and the GToolkit, and I owe it to myself to learn a lot more about these projects. From what I do know, they're seemingly the only things I can point to that share very many of the goals I have with my project, and have run into many of the same questions, and best of all have satisfying answers to those questions. To that end — I'd love to know what projects you are looking to as the high bar. What, if anything, is the existing work outside your own immediate sphere (so not Smalltalk / Self, say) that you would like to borrow from or build on? (As an example / aside: I had a 4 hour drive today, and I re-listened to your episode of the FoC podcast. You talked a bit about the importance of having a single render tree, so that the visual tools, introspection, etc. all work universally, and there are no dead ends where you hit a flat <canvas>-like thing. I'm working on that very same problem right now, but I think my solution is different. I allow multiple render trees, so you can use whatever rendering technology best suits each kind of data — SVG for SVG, GL for 3d, HTML for documents, etc. But each tree must be nestable, and able to generate input, and must have a way to render the editor GUI, so that it can fully participate in editing, introspection, etc.) The idea of "looks" makes a lot of sense to me. I clearly see the need, and the utility of this approach. You then go on to mention...
In a way, a look is like a property of a prototype object (in Pharo, these would be called talents, or object traits). We find this to be quite powerful.
I don't quite follow this simile, though. And — are these "traits" the same as in Self, or have they changed in the time since?
t
I a glad it is of help. If you want a tour of GT, I’d be happy to provide one. About one rendering tree, we describe it here: https://medium.com/feenk/one-rendering-tree-918eae49bcff?source=friends_link&amp;sk=c0551af8504ee919c4d8c54c390eef49 In essence, we wanted to have visualizations as first class, and we wanted to be able to connect anything with anything live. That meant that graph layouts had to become regular layouts and that there should be no black boxes: for example, a text editor must be representable in the same tree, too. Once we had that tree, it meant that we had one way of propagating events and that we could affect and connect anything from anywhere. About traits/talents: traits offer a static composition mechanism (like interfaces with implementation). An object trait (or talent) is a mechanism for injecting behavior in a specific object only.
🍰 1