5 ms·
The Universal Design Pattern
- jwilliams 18y agoThis is very informative... great post.
- silentbicycle 18y agoWhile he is focusing on Javascript and only makes a passing reference to Lua, it's worth noting that it has a very flexible and efficient implementation of property maps (called "tables") as its primary abstract data structure. You can quite easily set up inheritance behavior for prototyping, along with read-only tables and several other things, by defining access hook functions in "metatables" (property tables for the tables themselves). See also: Chapter 16 (OO) in _Programming in Lua_. The first edition is available online: http://www.lua.org/pil/16.2.html http://www.lua.org/pil/16.2.html
- jcromartie 18y agoIndeed. Lua lets you do practically anything you want, because it only gives you the building blocks of an object system.
- silentbicycle 18y agoIt's not an elaborate undertaking, either: you can make an object system in just under a page of code. Here's a good example, with lots of commentary: http://www.erix.it/progutil/gpeddler2/help/oo.html http://www.erix.it/progutil/gpeddler2/help/oo.html
- deleted 18y ago[deleted]
- nuclear_eclipse 18y agoI always find myself loving Lua, while continually wishing that it had a larger standard library like Python's. Without all the batteries included, it makes a great embeddable language, but stands very poorly on its own. It'd be my language of choice otherwise.
- deleted 18y ago[deleted]
- silentbicycle 18y agoSame here. Have you looked at LuaRocks, though? (http://www.luarocks.org/ http://www.luarocks.org/) It automatically grabs and installs packages, a la CPAN. It will take some time for there to be libraries for everything, of course, but the infrastructure is there.
- pchristensen 18y agoHooray! Some of my faith in Hacker News is restored. Every time I see a Yegge posted with a couple comments, I'm afraid that they will be complaints about how long it is. This time, they're about the article. Thank you for keeping it positive!
- Sujan 18y agobut well, it is looooong, isn't it? ;)
- pchristensen 18y agoBe grateful: "I considered splitting it into 3 articles, but instead I just cut about half of the material out. (Jeff and Joel: seriously. I cut 50%.)"
- knarf 18y agobut it comes with a table of contents. ;) maybe he should always include one
- JulianMorrison 18y agoIt's a very short book.
- river_styx 18y agotl;dr
- andreyf 18y ago...none of these modeling schools is "better" than its peers. Each one can model essentially any problem. There are tradeoffs involved with each school... Who are you and what have you done with Steve Yegge!? The Pulitzer Prize it won doesn't nearly do it justice. It's one of the greatest and most unique works of imagination of all time. Ah, there he is :)
- nihilocrat 18y agoThat's a neat post, the talk about Wyvern gets me really excited because game programming is my primary domain of interest. Someone please enlighten me; is the property model pretty much just reverse or non-hierarchical OO? Instead of saying "J.T. inherits from football player" you say "football player doesn't really exist, J.T. just inherits from a bunch of objects which are instances that have the properties of a football player"? The difference here is that inheritance is more like a node graph and a not top-down hierarchy, where the only real root object is the super-generic "object" object. If this is true, what about the "Chieftain" example Yegge said he left out? Is there a prototype called "Chieftain" which objects can inherit, but which alone doesn't fully implement a game object? Is it the case that you can't have "Chieftain" objects running around, as they only have all the properties needed when they are, for example, an "Orc Chieftain"?
- silentbicycle 18y ago> The difference here is that inheritance is more like a node graph and a not top-down hierarchy, where the only real root object is the super-generic "object" object. Right, although there isn't necessarily an Object that everything inherits from. You have an object, whose properties (both value fields and methods) are contained in a string-keyed table. If you want to inherit from it, you create another (probably via a method called "new") which defers to it when anything tries to find keys the new object hasn't overridden. If you think of the initial object as a Class object that instantiates instances, that's the idea, but you don't need to have an explicit class for something you'll only ever have one instance of - you can just build it in place. (Want a singleton? Don't give it a method that spawns new instances. Done.) It's more generalized than OO systems in which Classes and instances are two fundamentally different things. It may be helpful to read the chapter on OO in _Programming in Lua_ (linked above): It has a very concise intro to prototype-based OO. Lua may also be worth a look since you're interested in game development -- it is quite popular as an embedded scripting language in the game industry (and a pretty cool language in general, I think :) ). Also, see: http://c2.com/cgi/wiki?ClassesPrototypesComparison http://c2.com/cgi/wiki?ClassesPrototypesComparison
- groby 18y agoIf game programming is your interest, you might want to also look at Scott Bilas presentation for a "data-driven object system": http://www.drizzle.com/~scottb/gdc/game-objects.ppt http://www.drizzle.com/~scottb/gdc/game-objects.ppt They implemented pretty much what Steve is describing for Dungeon Siege. (Presentation was in 2002, so they started on it probably around 2000. Take that for "no earlier references", Steve ;) I vaguely recall that Thief used a similar system, too. There's also at least on "NextGen" game that uses that system that I'm aware of. It's pretty powerful (and makes it incredibly easy to shoot yourself in the foot) As for the "Chieftain" example - it's usually solved by providing multiple prototypes for an object. With all the ensuing uglyness.
- andreyf 18y agoUnfortunately Emacs doesn't support any notion of prototypes. Sure it does - just cons stuff onto assoc lists. I think PG mentioned this at the end of his "Arc lessons" essay.
- silentbicycle 18y agoTrue, but note that alists run in linear time. They're great for some things, but you probably don't want one with thousands of entries. You could use hashtables instead, but the syntax for hashtables in Emacs Lisp is cumbersome.
- palish 18y agoI've only had a small amount of experience with Lisp, so I'm just curious: would macros solve syntactic problems like that?
- silentbicycle 18y agoNot really. There isn't really any major reason why you'd need to wrap it in a macro, because it's not enough code to be worth running at compile time, and you don't need to control evaluation order. The bigger problem in elisp is that it doesn't have any kind of remotely sane namespacing, so instead of being something like Hashtable.make and Hashtable.set (which you could alias to HT.make and HT.set if you like), functions are either scattered all over the one global namespace or are all prefixed with cumbersome-package-name-. You could alias them all individually, but at that point it really doesn't contribute much to readability. The potential solution probably involves read macros, which (for example) convert 'STATE to (quote STATE) at read-time. Having read macros that could convert e.g. x[23] to (nth 23 x), x['key 'val] to (puthash 'key 'val x), etc. would be quite enough, but read macros are prefix, and [23]x really doesn't do it for me. (I'm experimenting with adding postfix read macros to a Scheme-ish interpreter of mine, but I haven't found a good way to make it fit the rest of Lisp comfortably yet.)
- amix 18y agoA thing I have noted is that every time I code in Java I feel handicapped for the lack of proper syntactic sugar for maps (I mostly code in JS/Python where maps are used for _all_ kinds of things (and hacks)). Anyway, great post.
- silentbicycle 18y agoDitto with Lisp, actually. Maybe something good could be done with read macros, but |(table 'key) -> (lookup table 'key) just doesn't do it for me. Any ideas? Lisp has alists, but (as noted elsewhere) they search in linear time. Python, Lua, and JS all have syntactic sugar for maps, and I think it makes a really big difference. They're quite versatile. Lua's table.key -> table["key"] sugar for all string keys is particularly nice.
- jimbokun 18y agoClojure has squiggly brace syntax for map literals, and multiple shortcuts for map lookups. E.g. both (map :key) or (:key map) return the value for :key in map (I think). Arc has similar syntax shortcuts for hashes (but sticks with parentheses): http://ycombinator.com/arc/tut.txt http://ycombinator.com/arc/tut.txt arc> (let h (obj x 1 y 2) (h 'y)) 2
- gcv 18y agoDon't know if this will do what you want, but these two reader macros add syntactic sugar for Common Lisp's aref and gethash forms. You should put these definitions in an eval-when. Disclaimer: I haven't used these in a while (not programming in Lisp at the moment, alas), so they may have some limitations which I have forgotten. (set-macro-character #\] (get-macro-character #\))) ;; Array syntax: [array-name array-references] is equivalent to ;; (aref array-name array-references) (set-macro-character #\[ #'(lambda (stream char) (declare (ignore char)) (destructuring-bind (array-name &rest array-references) (read-delimited-list #\] stream t) `(aref ,array-name ,@array-references)))) ;; Hash table syntax: #[hash-table hash-key &optional default] is ;; equivalent to (gethash hash-key hash-table &optional default) (set-dispatch-macro-character #\# #\[ #'(lambda (stream subchar arg) (declare (ignore subchar arg)) (destructuring-bind (hash-name hash-key &optional (default nil)) (read-delimited-list #\] stream t) `(gethash ,hash-key ,hash-name ,default))))
- yummyfajitas 18y agoJust a note, there is a python library implementing something very similar to this. It's quite nice, I use it regularly. http://code.enthought.com/projects/traits/ http://code.enthought.com/projects/traits/
- yters 18y agoWhoa, what a coincidence. I thought of using this for a major programming project I'm doing, without any idea whether it was a good idea or not. I've been having some serious doubts as I've been implementing it, so this article gives me a sense of validation.
- streblo 18y agoEvery time I read one of Steve's blog posts, I realize how little I know about software development.
- silentbicycle 18y agoHere are a couple more links with good discussion about prototype-based programming: * http://www.c2.com/cgi/wiki?PrototypeBasedProgramming http://www.c2.com/cgi/wiki?PrototypeBasedProgramming * http://www.c2.com/cgi/wiki?ClassesPrototypesComparison http://www.c2.com/cgi/wiki?ClassesPrototypesComparison SY is mostly talking about prototype-based programming in terms of Javascript, but it is also well-supported in some other languages, especially Lua (The chapter on OO in _Programming in Lua_ is IMHO the clearest explanation of prototypes I've found.), and it's probably possible to implement an inefficient-but-good-enough-for-brainstorming version in most languages.
- dhotson 18y agoThanks for the links... I love the old c2 wiki. There are some real gems in there. :)
- jcromartie 18y agoIt's only old in the sense that it has been there for a long time. It's still active and updated frequently.
- deleted 18y ago[deleted]
- peregrine 18y agoI just bought GEB cause its the 3rd time I've been suggested to read it. Good ol used books.
- qqq 18y agoMy comment on how this is related to epistemology: http://curi.us/blog/post/1339-steve-yegge-on-epistemology http://curi.us/blog/post/1339-steve-yegge-on-epistemology
- mjnaus 18y agoDamn, did someone actually read this whole thing?
- phaedrus 18y agoYou should look at "Io," a language based entirely on this modeling philosophy: http://www.iolanguage.com/ http://www.iolanguage.com/ I have to disagree with people who say class based modeling is "intuitive". It only seems intuitive after you've been steeped in OO practices for years. (It certainly isn't intuitive to many first or second year CS students!) But prototype based modeling, on the other hand (prototype modeling is Io's term for yegge's Universal Design Pattern) is something that I think is intuitive, because there are no classes, only objects, and making a new object is just a matter of cloning an object you already have and adding to it.
- arockwell 18y agoWhat I have always thought is dangerous is that class modeling only seems intuitive when discussing everyday concrete objects. Your average CS student does not have a problem understanding that a Car has an engine and 4 wheels and is a type of automobile. However, when modeling more abstract concepts getting the design correct is usually very nuanced.
- cousin_it 18y agoThe post reminded me of Will Thimbleby's MISC, an experimental Lisp-like language with maps instead of lists. Linky: http://will.thimbleby.net/misc/ http://will.thimbleby.net/misc/ (Java alert!)
- dmoney 18y agoPerhaps Greenspun's Tenth Rule ("any sufficiently complex C program contains an.. implementation of half of Common Lisp") applies as well to Java programs containing JavaScript. The question is whether Lisp and JavaScript contain each other.