Re: Embrace polymorphic builtins, for they are cool.
I would argue that eval BLOCK and eval STRING are closer than indicated by Mr. Schwern. In either case, you supply an argument which contains code, and that code is executed. As a small amount of protection from this dynamic element, fatal errors within the eval()ed code are trapped and prevented from causing the entire program to die. Whether the code is a string or a block doesn't alter the behavior of eval() other than by changing the point in time at which the argument code is compiled. That you can use what is really a side effect of eval's behavior in conjunction with deliberately-generated fatal errors to implement a kind of exception system doesn't change the fact that eval() is doing the same thing in both cases. Thus, it is good polymorphism. (I would say that the practice of using eval/die to provide an exception system is itself at best unclear, though that can be mitigated by the use of modules like Error.pm; but that doesn't mean there's a problem with the behavior of eval). However, I agree that close(variable) is less justifiable. I know what it means to close a file (even if only because I've been steeped in the world of computers and their filesystems for years; the analogy to physically closing a paper folder is loose at best), but the ideas of "closing" and "variable" don't go together in my head to form any kind of coherent concept. If I wanted to make variable read-only, I would expect to do it by setting the read-only attribute on that variable, which I would further expect to do the same way I would set any other attribute at any other time. Orthogonality has its good points, even in Perl; you just shouldn't be afraid to veer off diagonally when it makes sense. I don't think close(var) makes sense. -- Mark J. REED<[EMAIL PROTECTED]>
Re: Embrace polymorphic builtins, for they are cool.
> > Now look at eval. When acting on a string, it compiles and runs it as > code. When acting on a block, it traps any errors and prevents dying. > You may be able to come up with some weak analogies between the two, > but they're two different functionalities. i have nothing to add. you obviosly want to scrap eval-block for try. This is turning into a religious dispute. > Different object, same action: ok > Different object, different action: not ok > > > close (IO) # closes an open stream, returns > > # true on success or false on failure, > > # sets $! on failure > > > > close (\$) # overwrites the ASSIGN method of the > > > close. Closing a filehandle means you're no longer going to read > and/or write to it (depending on how it was opened). Closing a > variable means you're no longer going to write to it... but reading is > ok. The analogy is there, but its not a particularly strong or > obvious one, and there's the jarring difference that you can no longer > read from a closed filehandle, but you can read from a closed variable. > You've got to be careful with polymorphism and ensure that you've got > strong analogous action in all cases. Not just because its clever or > you like the name. This is not to say we shouldn't have polymorphic > built-ins (we already have more than you might think) but they must be > chosen with extreme care. So I take it that you object wholeheartedly to C++ Streams libraries using << and >> for IO operations because even though there is never any confusion, since bitshifting file handles is silly, it is in your terms WRONG? I think the limited set of objects that close(filehandle) is defined on makes it a perfect candidate for overloading with something completely different, just like the bitshift operators were overloaded for file ops in C++. I will continue to use it as described in discussion of How Capabilities Might Work In This Context until whacked over the head with a better keyword. > Some more counter-examples... un/pack() on a filehandle could compress > and decompress the file! It might be perfectly logical if un/pack > didn't already do something completely different. > > Some good examples... delete/exists work on both arrays and hashes. > delete() completely removes an array/hash element, exists() checks to > see if an array/hash element has been populated (even if its > undefined). The details might start to diverge a bit, but the basic > meaning doesn't change. > > Homogeneous operators are potentially confusing (just because English > has homonyms doesn't mean its not confusing) but not all polymorphic > functions are homonyms. Find the ones which retain their basic > meaning across all their objects, those are the good ones. > > PS delete() and exists() are also polymorphic, as is reverse(), > chomp(), chop(), goto() and die(). There are probably more, but I > can't think of them, probably because they mesh so well we don't even > think about it. You could consider functions which have default > arguments as polymorphic, then there's lots and lots of polymorphism > in Perl. But I digress. Great! So you agree that we need better polymorphism in prototype and dispatch of user-defined routines? -- David Nicol 816.235.1187 Signature closed for repaving
Re: Embrace polymorphic builtins, for they are cool.
On Mon, Jun 11, 2001 at 09:18:14PM -0500, David L. Nicol wrote: > But I'm digressing. What I want to talk about is overloaded builtins. > > I recently suggested that C be overloaded to make its argument, > when its argument is not a filehandle, become read-only. An objection > was made to this, on the grounds that homonymous operators are confusing, > with eval block and eval string being given as an example of something > that is confusing. > > This post is intended to be a response to that objection. > > Natural language contains many homonyms. This is rarely, outside of > dramatic plots, a problem, as there are other indicators, up to and > including requests for clarification, but generally "context," to > guide us human beings as we apply our common sense to the great > questions of What Is Fair and What Is Right without taking wrong turns > or digressing into discussions of propagandistic trends in modern > journalism while dividing chocolate cake evenly among party guests. > > Okay? > > C (string/block) is but one. I'd hold this up as a failure of polymorphic functions. eval STRING and eval BLOCK do completely different things and people associate their behaviors, merits and flaws together because they have the same name. > C might be considered another. Another fine counter-example. Who understands all the different things that do() does?? Its particularly bad because of the name. "do" is about as generic as "foo". It could mean anything. > overloading C to do what beginners expect. This is an example of polymorphism done for good. Why? First, there's a relatively obvious expectation of what length() will do with a string and an array (a hash might be a little less obvious). Second, and much more subtle, is that while the object of the function changes, its basic functionality does not. Its very important. Think of it as a verb (function) and object of that verb (arguments). length() is the verb, a string or array is the object. When acting on a string, you get the number of characters in the string. When acting on an array, you get the number of elements in the array. Basically the same operation, adapted for the object. This is polymorphism for Good. Now look at eval. When acting on a string, it compiles and runs it as code. When acting on a block, it traps any errors and prevents dying. You may be able to come up with some weak analogies between the two, but they're two different functionalities. Different object, same action: ok Different object, different action: not ok > close (IO) # closes an open stream, returns > # true on success or false on failure, > # sets $! on failure > > close (\$) # overwrites the ASSIGN method of the close. Closing a filehandle means you're no longer going to read and/or write to it (depending on how it was opened). Closing a variable means you're no longer going to write to it... but reading is ok. The analogy is there, but its not a particularly strong or obvious one, and there's the jarring difference that you can no longer read from a closed filehandle, but you can read from a closed variable. You've got to be careful with polymorphism and ensure that you've got strong analogous action in all cases. Not just because its clever or you like the name. This is not to say we shouldn't have polymorphic built-ins (we already have more than you might think) but they must be chosen with extreme care. Some more counter-examples... un/pack() on a filehandle could compress and decompress the file! It might be perfectly logical if un/pack didn't already do something completely different. Some good examples... delete/exists work on both arrays and hashes. delete() completely removes an array/hash element, exists() checks to see if an array/hash element has been populated (even if its undefined). The details might start to diverge a bit, but the basic meaning doesn't change. Homogeneous operators are potentially confusing (just because English has homonyms doesn't mean its not confusing) but not all polymorphic functions are homonyms. Find the ones which retain their basic meaning across all their objects, those are the good ones. PS delete() and exists() are also polymorphic, as is reverse(), chomp(), chop(), goto() and die(). There are probably more, but I can't think of them, probably because they mesh so well we don't even think about it. You could consider functions which have default arguments as polymorphic, then there's lots and lots of polymorphism in Perl. But I digress. -- Michael G. Schwern <[EMAIL PROTECTED]>http://www.pobox.com/~schwern/ Perl6 Quality Assurance <[EMAIL PROTECTED]> Kwalitee Is Job One kiloconway: unit of extreme mind expansion. Equal to 1024 conways, one kiloconway gives the sensation that all of the quantuum particles in your