From: Mathieu Bouchard Date: 2005-04-02T18:08:51+09:00 Subject: Re: Hash::MixIn and Python style Object#dict On Sat, 26 Mar 2005, Florian Gross wrote: > Mathieu Bouchard wrote: > > MetaRuby (http://artengine.ca/matju/MetaRuby/) provides that, with > > examples implementing #undo/#redo, BitArrays, InstanceVariablesHash, > > MethodsHash, FileAsString, ProcAsArray, ... And those examples are all > > very short. > Certainly still an interesting project. Does it work properly on 1.8? No. > Is documentation available online? All the doc there is, is in the tarball. > I agreed here, but found .fetch and .store to be relatively simple. The > only complex thing is that .fetch can take fallbacks in the form of > Objects or blocks as well. I'm not sure how to handle that, but I guess > the situation is not too bad right now. > I'm not sure what the .put_seq and .get_seq methods do though. Do they > somehow replace .keys and .delete? No, in the SimpleHashP contract, it's .each_key and .remove that play those roles, and then .each is made using .each_key, and .delete is made using .remove. The .put_seq and .get_seq methods are declared only in the SimpleArrayP and SimpleStringP contracts. They implement only the a[i,n] case, whereas .put and .get implement only the a[i] case. Basically the two seq methods are there for efficiency. The actual full [] and []= have more cases than that, that get implemented in terms of those two. > How would the mixin-based contract look? Ideally, it would be a set of around-methods that first check the precondition, then call super, then check the postcondition; but since Ruby only supports a small subset of Lisp method-lookup (1), it doesn't support the aspect-oriented features (AOP) of Lisp. There are cool Ruby packages like AspectR and DbC that do a good job of coercing Ruby into doing it, and Ruby tends to be quite docile for that kind of thing, but I wanted to try a different strategy. So instead the contract is a non-class module (2) which you have to include in a subclass of your implementation (and not in the implementation directly, which would either require AOP features, method-renaming, or another trick). For example, class MyHash; include HollowHash # (3) def each_key(&b) # blah blah blah end # further blah end class MyVerifiedHash < MyHash; include SimpleHashP; end h1 = MyHash.new # unchecked (faster) h2 = MyVerifiedHash.new # checked (safer) That's it. --- Notes: (1) Namely, it's got something fairly close to Lisp's (call-next-method) in the shape of "super", but it doesn't have multiple-dispatch nor method-combinations and it only supports a subset of backtracking-inheritance because of the following reason ((2)). (2) Ruby requires the programmer to state explicitly whether a module is instantiable or not, and those that are, are called classes, and there are further restrictions that you know regarding what can inherit from what. Those restrictions are not present in CommonLisp, but Ruby programmers seem to prefer something more complicated. (3) HollowHash is called like that because my English is bad. I actually had ShallowHash in mind, which is 10 times more meaningful, and rhymes. Nowadays I'm thinking about names like AbstractHash and HashShell. Especially, the concept of kernel/shell separation as it appeared in 70's OSes like Multics and Unix reflects pretty much the nature of the beast: have a small set of low-level features that are have simple interfaces, and a wrapper around them so that they become convenient to use. An important note is that a HashShell (HollowHash) is the thing that stays the same, while the kernel gets specialised for a given task/behaviour. In laymen's terms, it's like you always interact with your system in the same way using Bash or Konqueror, no matter whether you're on Linux, FreeBSD, MacOSX, Cygwin, or QNX. _____________________________________________________________________ Mathieu Bouchard -=- Montr�al QC Canada -=- http://artengine.ca/matju