[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: orthogonality and generalized references (was Re: Zen of Python)




Todd, is Icon's symmetry of success and failure really the proper
path here? Isn't it the case that you want something like 

 (hash-table-get HT 'foo
   ; failure thunk: 
   (lambda () (hash-table-put! HT 'foo 42))

so that the reader recognizes the sequence of success and fail
computations? 

-- Matthias


At Mon, 27 May 2002 17:57:55 -0700, "Todd Proebsting" wrote:
> Ages ago I posted to this list about goal-directed evaluation in Icon.
> This "ifAbsentPut" discussion will, I hope, allow me to express another
> advantage of goal-directed evaluation.  In Icon, the ifAbsentPut idiom
> is the following simple expression---Icon has only expressions, and not
> statements.
> 
> /dict["foo"] := 42
> 
> To understand this statement, you must understand the unary '/' operator
> and the notion of goal-directed evaluation.  The '/' operator computes
> the l-value (if one exists, otherwise the r-value) of its operand IFF
> the r-value is not null.  If the r-value is null, then the operation
> fails.  With goal-direction, an operand failing causes its parent
> operation to do whatever it is supposed to do when the operand fails.
> (The rules for what to do are simple and regular, but I'm not going to
> go into them here.)
> 
> In this case the parent is the assignment operator, which itself will
> fail when its left operand fails.  If and when the right operand and
> left operands have both succeeded, the assignment takes place and the
> r-value is produced as a value.
> 
> So, the assignment above will assign the value 42 to dict["foo"] when
> dict["foo"] is null and simply fail when dict["foo"] is non-null.  Note
> that the l-value is computed only once.
> 
> The '/' operator can, of course, be applied to any expression.  Any Icon
> programmer would recognize the idiomatic use of '/' above.  I find it
> superior to the other schemes that I've seen.
> 
> I wish other languages exploited the fundamental difference between
> success and failure that is essential to Icon.  It's awkward to code
> your way around their absence in other languages.
> 
> Todd
> 
> -----Original Message-----
> From: Kragen Sitaker [mailto:kragen@pobox.com] 
> Sent: Monday, May 27, 2002 4:56 PM
> To: ll1-discuss@ai.mit.edu
> Subject: orthogonality and generalized references (was Re: Zen of
> Python)
> 
> 
> Avi Bryant writes:
> > [in Ruby]
> > dict['foo'] ||= 42
> > [in Smalltalk, "extremely regular and explicit"]
> > dict at: 'foo' ifAbsentPut: [42].
> > ...
> > What's the equivalent Python idiom?  My guess is that it will be 
> > either less regular, or less explicit, or both.  I'm not trying to 
> > pick on Python, I'm just trying to point out that there is no simple 
> > relationship between regularity, explicitness, and succinctness; it's 
> > entirely possible to have all three.
> 
> Python uses roughly the Smalltalk approach, although (like Perl) it
> doesn't provide a convenient way for you to avoid evaluating the default
> value in the case that the value is already present:
>     dict.setdefault('foo', 42)
> 
> I don't quite understand what you mean by "regular" or "explicit"; the
> Ruby/Perl idiom is less explicit, I agree, but it appears to me to be
> more regular --- the Smalltalk/Python idiom here is to use a
> special-purpose method, while the Ruby/Perl idiom is a combination of
> three orthogonal language features that have nothing to do with
> dictionaries or hashes: the boolean 'or' operator's return value, the
> false result of looking up a nonexistent index in a dictionary or hash,
> and the augmented assignment operators.  As a result, you can also say
> (in Perl):
> 
> $x ||= 42;    # ordinary variable
> $y[3] ||= 42; # list reference
> 
> Common Lisp has the notion of a "generalized reference", such as
> (gethash "foo" dict), which can be set with setf or read by evaluation;
> and it has boundp and makunbound, but they only work on symbols, not
> generalized references.  In a CL dialect where boundp and makunbound
> (somehow --- they standardly evaluate their arguments, so (boundp
> (gethash "bar" x)) will tell you whether the symbol (gethash "bar" x)
> returns is bound or not) worked on generalized references, you could
> write a setdefault macro that would allow you to say things like this:
> 
> (setdefault (gethash "foo" dict) 42)
> (setdefault x 42)
> (setdefault (nth 3 y) 42)
> 
> giving you the same level of regularity and orthogonality you have in
> Perl and Ruby, along with the same level of explicitness you have in
> Python (and, arguably, Smalltalk, although I think at:ifAbsentPut: is
> more explicit than setdefault).
> 
> (I don't know Common Lisp; apologies for any mistakes.)
> 
> I wish I had a language where I could define this "setdefault"
> operation; it requires Common Lisp's ability to define new operations on
> generalized references (for example, with macros; you can do it crudely
> in C++ with a reference or in Forth with a raw memory address) along
> with Python's ability to get, set, undefine, or check definedness of
> generalized references. [0] Is there such a language?
> 
> 
> [0] Python conflates providing an initial value and replacing an
> existing value with a new value, unfortunately, and provides 'check
> definedness' by raising an exception when you try to get an undefined
> value.  Also, Python's generalized references are variables, object
> attributes (x.y), and indexing expressions (x[y]), not general function
> calls; this sounds more limiting than it is.
> 
> -- 
> /* By Kragen Sitaker, http://pobox.com/~kragen/puzzle2.html */ char
> a[99]="  KJ",d[999][16];main(){int
> s=socket(2,1,0),n=0,z,l,i;*(short*)a=2;
> if(!bind(s,a,16))for(;;){z=16;if((l=recvfrom(s,a,99,0,d[n],&z))>0){for(i
> =0;i<n;
> i++){z=(memcmp(d[i],d[n],8))?z:0;while(sendto(s,a,l,0,d[i],16)&0);}z?n++
> i++:0;}}}