Re: Stringification, numification, and booleanification of pairs
Juerd wrote: But will they also see foo ~ $bar as something different from foo$bar? They ought to, since the two are different in Perl 5. For example: my @bar = 'bar'; print [EMAIL PROTECTED]; print foo[ . @bar . ]baz\n; And what context does foo{ $bar } use? Stringification, of course. No interpolation is occurring. In my opinion, making the string value in interpolation different from the value in Str context is madness. It's dwimmery. Which often looks like madness until you realize that it's just a reflection of how most hackers think. ;-) Damian
Re: Stringification, numification, and booleanification of pairs
Damian Conway skribis 2005-09-24 8:31 (+1000): In my opinion, making the string value in interpolation different from the value in Str context is madness. It's dwimmery. It's dwymmery, or dwdmmery indeed. Not at all what I mean, am likely to mean, or will ever mean. Which often looks like madness until you realize that it's just a reflection of how most hackers think. ;-) This calls for a poll, because I believe nothing of this most. Hackers on this list, what do you think? Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: Stringification, numification, and booleanification of pairs
Damian Conway skribis 2005-09-24 8:31 (+1000): They ought to, since the two are different in Perl 5. For example: my @bar = 'bar'; print [EMAIL PROTECTED]; print foo[ . @bar . ]baz\n; This does not compare stringification to interpolation. It compares scalarification to interpolation. Interpolation (stringification) was needed because Perl 5's arrays weren't as smart as Perl 6's, and didn't usefully stringify in string scalar context. @foo Context Perl 5 Perl 6 numeric number number stringnumber join scalarnumber ref This huge difference in how smart an array is makes it kind of useless to take Perl 5 as an example of how arrays should behave in Perl 6, because that would also dictate that foo ~ @bar end in the number of elements in @bar. Bad idea. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: Stringification, numification, and booleanification of pairs
On Sun, Sep 25, 2005 at 12:52:08PM +0200, Juerd wrote: Hackers on this list, what do you think? I think separating the two is extremely confusing. I do not see any uses for it, but maybe I am not thinking hard enough. -- wolverian signature.asc Description: Digital signature
Re: Stringification, numification, and booleanification of pairs
On Sun, Sep 25, 2005 at 12:52:08 +0200, Juerd wrote: Damian Conway skribis 2005-09-24 8:31 (+1000): In my opinion, making the string value in interpolation different from the value in Str context is madness. It's dwimmery. It's dwymmery, or dwdmmery indeed. Not at all what I mean, am likely to mean, or will ever mean. Which often looks like madness until you realize that it's just a reflection of how most hackers think. ;-) This calls for a poll, because I believe nothing of this most. Hackers on this list, what do you think? I think there is no merit in separating the two since you can't have a default interpolation. There is no one canonical right way to visually render any object as text. Based on this claim I think that if we make 2 stringication operations, one pure and one interpolated, we should have roughly 30 interpolation operators, for each possible scenario of interpolation (interpolation to STDERR, interpolation when we're printing many other lines, interpolation into a string that gets sent to a file (we can use type inferrence)), and so on and so forth. What I'm getting at is that the distinction between interpolation and stringification is between the purposing of the stringified forms - programmatic or visual. This distinction is wrong to make without separating the types of the output, since there are two implicit constructors for the Str data type, which are not directly visible to the naive user. Furthermore, since the two are combinable, e.g. foo${bar}gorch ~ $moose; the train of thought the user follows is that of taking four elements (foo, $bar, gorch, $moose) and making one big result out of them. The separation of interpolation from stringification here is tricky because it actually does 2 different operations instead of seemingly one big operation on four operands. For every Oh crap, i get it i've said in my perl 5 programming career i think i'll have about 3-4 just related to these interpolation semantics in perl 6. This also stops users from picking between interpolation and concatenation on a case by case basis for the purpose of enhancing readability. On top of that there is the fact that perl 5 people come to expect that ($foo) means (.$foo), except that the first version is easier to read. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me groks YAML like the grasshopper: neeyah!! pgp7w51MXUWh8.pgp Description: PGP signature
Exceptuations
Hi, Suppose I'm writing a file browser, with a pane on the left to display the filesystem hierarchy, and a frame on the right to preview the file. Suppose I have a convenience function, preview_file which takes a path and returns a value that the frame display view knows to render. Let's define this for HTML files, where the desired preview is a summary of the text: use Text::Summarize; use HTML::ToAscii; multi sub preview_file ($filename where /\.html$/ ) { my $handle = open($filename, :r); # might fail if $filename is unreadable return summarize(html2ascii(=$handle)); # might fail if HTML is invalid } And this code is called when the user clicks on a file in the pane: class NiftyUI { use fatal; method handl_some_click ($file) { $.right_frame.display(preview_file($file.name)); } method handle_event ($event) { $?SELF.dispatch_event($event); CATCH { when NiftyBackend::Exception { $?SELF.display_error_box($!); } default { die $! }; } } } With the current shape of the code if any of the possible failures in the backend code happen, they are reported in a message dialog. Now, let's say we would like to add a feature, that lets the user change the mode of the file if it's unreadable. Several approaches to doing this: * give the backend an abstract object, a Frontend of sorts: $frontend.ask_user(do you want to make the file readable?) * throw internal exceptions, and let the frontend handle the exception and retry the action: method handle_some_click ($file) { $.right_frame.display(preview_file($file.name)); CATCH { when IO::Errors::PERMISSION_DENIED { if ($?SELF.ask_user_to_chmod_file($file)) { make_readable($file); $?SELF.handle_some_click($file); # retry the event } else { die $! } } } } I propose a new model - each exception has a continuation that allows it to be unfatalized. The exception object has info on whether the fatality of the exception was due to a die, or a use fatal, and lets the exception handler decide accordingly. Then we have code that looks like this: method handle_some_click ($file) { $.right_frame.display(preview_file($file.name)); CATCH { when IO::Errors::PERMISSION_DENIED { if ($?SELF.ask_user_to_chmod_file($file)) { make_readable($file); $!.continue(open($file, :r)); # the return value of the failed open is # overridden by the return value of this (hopefully successful) open. } else { die $! } } when HTML::ToAscii::Exception { # badly formed $!.continue(The HTML file contained a syntax error); # this string is passed to summarize instead of the undef exception object } } } The value this has is in handler cascading... If, for example, make_readdable($file) failed too, then an exception handler around handle_some_click could handle display a sudo box, to try it again, and eventually continue back into the make_readable($file) call, which will then continue into the failed open. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me tips over a cow: neeyah!! pgprazW7gmwVh.pgp Description: PGP signature
Re: Exceptuations
In order to support continuable exception generators, here is a style guide for exception values, and an observation on what exceptions should support at the language level: * Exceptions should preserve data All exceptions should contain as much of the original data that caused them... With Luke's new theory proposal, storing the argument tuple for the call the raised the exception is logical. For example, for a Permission Denied error raised in open() we should have access to the filename that we tried to open, and the mode we tried to open it with. * Each thrown exception should contain the value of $! from before it was thrown * Each thrown exception has to know whether it was thrown because of 'use fatal' or because of an explicit 'die' * fail should be used except for very strict conditions * use fatal should be encouraged by the documentation, for one liners, scripts, and full blown apps. * Context data should be overridable at the exception object level Carp and friends should be implemented not by using a different keyword than fail, but failing with a value that specifies a certain context. sub croak (*$a) { # tuples again fail Exception.new(*$a, :position($?CALLER::CALLER::POSITION)); } * fail should cascade such that every time a block is left with a failing return value, the block's caller should be checked for use fatal. * When continuing into an exception, the parameters to the continuation are substituted for the error. use fatal; my $value = { fail foo; CATCH { $!.continue(bar); } } say $bar; Continuing into the exception with no arguments is like ignoring 'use fatal' for this specific exception, causing the failed value to propagate out of the fatalized block. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me wields bonsai kittens: neeyah pgpE7Wb5OOFbg.pgp Description: PGP signature
Re: Exceptuations
On Sun, Sep 25, 2005 at 18:11:22 +0300, Yuval Kogman wrote: In order to support continuable exception generators, here is a style guide for exception values, and an observation on what exceptions should support at the language level: And more... * Exception strings are for humans Humans need to know what happened in their own words. They have a hard time analyzing error codes, or constant names. Computers have a hard time analyzing strings, and prefer hard data. It should be easy to identify each error in a way that is meaningful to computers, and this way should be orthogonal to the string that is displayed to the user when possible. This means that it should be incredibly easy for the user to declare exception classes as they are used, perhaps by stealing goodness from enumish constructs, or somesuch. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: *shu*rik*en*sh*u*rik*en*s*hur*i*ke*n*: neeyah pgpcpkWrPtIwr.pgp Description: PGP signature
Re: Exceptuations - CPS explained
To ease the understanding of exactly how this might work, assume that perl 6 is really all continuation passing style under the surface (parrot is ;-). use fatal; my $x = do_bar(); do_foo(); sub do_bar { fail bah; } The way CPS works is really simple. The principal is that there is no concept of return. Instead, the call to do_bar, for example, gets an additional implicit parameter. This parameter is the code ref to the rest of the code, and could look something like this if deparsed: sub ($rv) { my $x = $rv; do_foo() } So do_bar knows to make a goto to that code ref with it's return value. Now, fail gets something similar - it gets the code ref which applies do_bar's passed in code ref, and it applies it the exception constructed from bah. Fail will also check first to see if the continuation might, at some level, use fatal. If it does, it takes a dynamically scoped value instead - the continuation for the last encountered CATCH block. When it throws the exception, fail will store the continuation it got (the $x = ... stuff) in the exception object. CATCH can then choose either to goto it's parent block's continuation (exit normally), or to goto the continuation stored in the exception object, which is indirectly the assignment to $x. Autrijus's example makes this clear (he prefers resume over continue): use fatal; my $x = { 1/0 * 3 CATCH { $!.resume(9) } }; # 27 What's happening is that infix:/ checks if it's divisor is 0, and if it is, it will fail. Fail has a continuation to 'multiply by 3 - exit from block - assign to $x', and it stores that in the exception object. Instead of gotoing to that continuation, it will instead take the last CATCH block that was relevant, in this case the only one. This one finds the continuation to * 3 etc in the exception object, and effectively augments the result of infix:/(1, 0) to be 9 instead of an undefined value. I hope this makes things clear. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me does not drink tibetian laxative tea: neeyah! pgpC58pLTHBic.pgp Description: PGP signature
Allomopherencing
Hmm... Making up these subjects is fun =) Anywho... Since type inferrencing is going to make into Perl 6, and allomorphism is very richly supported by the type system, i'm wondering on the nature of the optionality... What excatly do the users get to control? Are functions with '--' rich type signatures going to limit the user in any way? What should the functions in the prelude be defined as? Under strict type inferrencing, i'd expect this to be a compile time error: my $dog = Dog.new; if ($condition) { my Cat $c = $dog; } else { ... } since it's guaranteed to be a runtime error if $condition is ever true. Is there any situation where a compile time error is not a good thing to have? If allomorphism is enough such that the class that implements the actual integers, which does Str, Int, Num, Ord and all that for the yummy operations we can do on it, and expressions like foo ~ 42 ~ Bar are type safe, is there really any reason to ever not give compile time errors to type errors? Also, is it rational to say, within a lexical pragma, that such zealous allomorphism is prohibited, in order to get more rigid type semantics for that block? If so, how is this defined? On the other side of the spectrum, is there any situation where type safety is ever a bad thing, if it's inferred, and flexible? -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me supports the ASCII Ribbon Campaign: neeyah!!! pgpPThiBbNSi3.pgp Description: PGP signature
Re: Exceptuations
On 9/25/05, Yuval Kogman [EMAIL PROTECTED] wrote: I propose a new model - each exception has a continuation that allows it to be unfatalized. I think we've already talked about something like this. But in the presence of use fatal, it makes a lot more sense. Something comes to mind: use fatal; sub foo() { bar() } sub bar() { baz() } sub baz() { quux() } sub quux() { fail } { say foo(); CATCH { $!.continue(42) } } Exactly which exception is continued? Where do we cut off the call chain and replace our own value? This comes up again with open(). Let's say open is implemented with a series of five nested calls, the innermost which knows how to fail and propagate outwards. However, the programmer using open() has no idea of its internals, so it ought to override the return value of open() itself, rather than its utility functions. However, we can't go with outermost, because then you'd only be fixing the lexical call (say foo() above). So it's somewhere in between. Where? Luke
Re: Stringification, numification, and booleanification of pairs
On 9/25/05, Yuval Kogman [EMAIL PROTECTED] wrote: On Sun, Sep 25, 2005 at 12:52:08 +0200, Juerd wrote: Damian Conway skribis 2005-09-24 8:31 (+1000): In my opinion, making the string value in interpolation different from the value in Str context is madness. It's dwimmery. It's dwymmery, or dwdmmery indeed. Not at all what I mean, am likely to mean, or will ever mean. Which often looks like madness until you realize that it's just a reflection of how most hackers think. ;-) This calls for a poll, because I believe nothing of this most. Hackers on this list, what do you think? [...snip...] On top of that there is the fact that perl 5 people come to expect that ($foo) means (.$foo), except that the first version is easier to read. Yes, that's how I explain it to anyone who really needs to know, which is usually to someone asking about overloading. However, I see a useful difference between Str[ingification] and 'does Interpolate' or whatever that role might be. However, the names might want to change to protect the innocent. The Stringification of a UnixEpochTimestamp should probably be the same as its Integerization -- 12345678900. However, the Interpolation of it should be the locale-specific POSIX-style datetime string. Here's how I would do it if $Ashley == any(@Larry) The .as(Str) of an object would be its serialization -- what you would spit out for the Perl6 version of pickle/Storable/whatnot. Ideally, the Str representation would be lossless, informationally, so you could call the deserialize/unpickle (.from?) method using its return-value: my Thingy $foo .=from($thing); The Interpolate role's method would return the pretty-printed, possibly LOSSY presentation of the object's information. For example: my $color = new HTML::Color(magenta); if $color.as(Str) eq '#FF00FF' and $color eq magenta { $Ashley++; } So, to summarize, I want .as(Str) to be the lossless canonical representation, as well as the basis for the default .hash method, while Interpolate would be the pretty-printed localized lossy presentation Role. Ashley Winters
Re: Exceptuations
On 9/25/05, Luke Palmer [EMAIL PROTECTED] wrote: [...] Exactly which exception is continued? [...] Named restarts in Common Lisp appear to try to solve a related problem, if I'm skimming this thread correctly. :-) (see [1]). Michael [1] http://www.supelec.fr/docs/cltl/clm/node312.html#SECTION00330
Re: Allomopherencing
On 9/25/05, Yuval Kogman [EMAIL PROTECTED] wrote: Hmm... Making up these subjects is fun =) Very interesting. :) Under strict type inferrencing, i'd expect this to be a compile time error: my $dog = Dog.new; if ($condition) { my Cat $c = $dog; } else { ... } since it's guaranteed to be a runtime error if $condition is ever true. I can't accept that. While you can infer that $dog will be a Dog at that line of code, it isn't being enforced, which means no compile-time error. $dog is allowed to store any kind of data, and you only know what methods exist in Dog at compile-time. After all, I was planning to add a Dog::as(Cat) method at runtime. Yes, I'm a mad scientist. Muahahaha!!! In order to enforce that level of compile-time type safely, you should need to declare my Dog $dog, or stick a pragma up top: use sadistic inferencing; either of those declarations can disregard my potential for runtime tomfoolery, and abort the compiliation when there's something illogical. Ashley Winters
Re: Allomopherencing
On 9/25/05, Ashley Winters [EMAIL PROTECTED] wrote: On 9/25/05, Yuval Kogman [EMAIL PROTECTED] wrote: Under strict type inferrencing, i'd expect this to be a compile time error: I quoted but didn't read close enough. You DID say strict type inferencing. Never mind. :) Ashley Winters
Re: Stringification, numification, and booleanification of pairs
On Sun, Sep 25, 2005 at 10:59:38 -0700, Ashley Winters wrote: The Stringification of a UnixEpochTimestamp should probably be the same as its Integerization -- 12345678900. However, the Interpolation of it should be the locale-specific POSIX-style datetime string. Why? What value does the stringification of a date have as a stringified integer? If we were to implement such semantics, wouldn't it be wiser to print The time in seconds since the epoch is { +$time }? That's much more readable, obvious and nonsurprising, without being overly long or tedious. I would never say something like the time $time is ~ $time ~ seconds since the epoch That's simply absurd. Especially when the context of the string (the stuff it's being interpolated to - not the programmatic context) is not 100% self explanatory - then I would need to comment it. Here's how I would do it if $Ashley == any(@Larry) You mean eqv.. =( The .as(Str) of an object would be its serialization as is formatting, not serialization: $time.as('%d'); or something... I don't really know how this works For serialization you have the .perl method, which is roughly the same as Data::Dumper (code to be evaled), or some more heavy duty package (i expect Storable to have a pretty consistent interface). my Thingy $foo .=from($thing); my Thingy $foo = eval($thing.perl); The Interpolate role's method would return the pretty-printed, possibly LOSSY presentation of the object's information. Uhuh, which is a flawed concept, because whose to decide what should be lost? why does the perl prelude have to decide what's valueable and what can be lost during *stringification or interpolation* now, when this language is supposed to live for another 20 years? For example: my $color = new HTML::Color(magenta); if $color.as(Str) eq '#FF00FF' and $color eq magenta { $Ashley++; } $color.hex_triplet; # no alpha $color.name; # if we have one... or we can try to make one up (#ff0033 is bluish red ;-) I see no reason why these two should behave in anyway, except that one of them is the canonical format. There is no mnemonic device whatsoever to link interpolation to color naming, and stringification to hexadecimal representation. Why isn't the str method (255,0,255)? Why isn't interpolation more expressive and Dwimmy? So, to summarize, I want .as(Str) to be the lossless canonical representation, as well as the basis for the default .hash method, while Interpolate would be the pretty-printed localized lossy presentation Role. For localization we need another thing. I propose a new prefix operator, with some funny char we haven't used yet. It would be a part of the Localizable role, and it would return a Str. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me supports the ASCII Ribbon Campaign: neeyah!!! pgpbuSYDHJ9p9.pgp Description: PGP signature
Re: Exceptuations
On Sun, Sep 25, 2005 at 11:32:54 -0600, Luke Palmer wrote: Exactly which exception is continued? ... This comes up again with open(). So it's somewhere in between. Where? For the open() example I don't have a solution but I know in what direction to throw it: the same thing that makes croak appear to work from the caller =) Several things come to mind... First is this: (ugly) sub open { ... CATCH { fail $! }; # force it to go up } This is the most flexible, but also the crudest method. Another idea is to use the same namespace hopping logic that Carp does right now. This doesn't work for exceptions in the same class so it should be optional and off by default... Perhaps: fail error :package_boundry; # better word needed Another idea is to use a lexical pragme that delays all errors, which is like CATCH { fail $! } but more declarative: sub open { use fatal propagate; ... } For when it isn't specified, when doing evil things such as stepping into the continuation of an exception, we assume that the code doing the CATCH knows about the code that raised the exception at least something. Encapsulation is sort of maintained by specifying what kinds of operations are fixed.. For example, errors having to do with opening files are fixuppable by taking the arguments to open found in the exception, and trying to reopen the file after some fudging, and returning a handle. This is common knowlege about the interface of open, and we are simply saying that for the rest of the dynamic scope (dangerous, perhaps) we are trying to fixup every call to open that fails with this handler. This is no different than catching that exception in terms of encapsulation, except that the failure is defatalized. My claim is that just as you know the kind of error it is when you explicitly catch it for the purpose of reporting, you have the same knowlege when you are fixing. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me sushi-spin-kicks : neeyah pgpCOTXugoPT2.pgp Description: PGP signature
Re: Allomopherencing
On Sun, Sep 25, 2005 at 11:24:05 -0700, Ashley Winters wrote: I can't accept that. While you can infer that $dog will be a Dog at that line of code, it isn't being enforced, which means no compile-time error. $dog is allowed to store any kind of data, and you only know what methods exist in Dog at compile-time. After all, I was planning to add a Dog::as(Cat) method at runtime. Yes, I'm a mad scientist. Muahahaha!!! If you say my $pet = Dog.new; if ($condition) { $pet = Cat.new; } my Car $spot = $pet; Then $pet's type is inferred to Cat|Dog, and must be able to contain either of those, but that is still not a Car. I'm assuming under use optimize where everything is closed.; In order to enforce that level of compile-time type safely, you should need to declare my Dog $dog, or stick a pragma up top: That's the point of my question - why? What do I lose by inferrencing? -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me climbs a brick wall with his fingers: neeyah! pgpEkBSPIsL67.pgp Description: PGP signature
Re: Stringification, numification, and booleanification of pairs
On 9/25/05, Yuval Kogman [EMAIL PROTECTED] wrote: On Sun, Sep 25, 2005 at 10:59:38 -0700, Ashley Winters wrote: The Stringification of a UnixEpochTimestamp should probably be the same as its Integerization -- 12345678900. However, the Interpolation of it should be the locale-specific POSIX-style datetime string. Why? What value does the stringification of a date have as a stringified integer? If we were to implement such semantics, wouldn't it be wiser to print The time in seconds since the epoch is { +$time }? That's much more readable, obvious and nonsurprising, without being overly long or tedious. It's not a Date, it's a UnixEpochTimestamp. I'm choosing my classes for maximum expositive effect, and in this case a UnixEpochTimestamp is explicitly defined as number-of-non-leap-seconds-since-1970. You probably need to either .strftime(), .posix_localtime(), posix_gmtime() or .as(Perl6::Time) to get a proper formatting. Here's how I would do it if $Ashley == any(@Larry) You mean eqv.. =( Ouch. You're right, but that's a painful adjustment. The .as(Str) of an object would be its serialization as is formatting, not serialization: $time.as('%d'); or something... I don't really know how this works For serialization you have the .perl method, which is roughly the same as Data::Dumper (code to be evaled), or some more heavy duty package (i expect Storable to have a pretty consistent interface). Yes, .perl, .json, .xml, .repr, whatever. my Thingy $foo .=from($thing); my Thingy $foo = eval($thing.perl); This should really really really be discouraged and/or prevented. This will be a Perl6 Worst Practice in short order. Please, consider: my Thingy $foo = eval:data $thing.perl or eval:json $thing.json or eval:xml $thig.xml eval() itself feels like the wrong function for doing this. I'm trying to parse(), not eval(). But, I digress... The Interpolate role's method would return the pretty-printed, possibly LOSSY presentation of the object's information. Uhuh, which is a flawed concept, because whose to decide what should be lost? why does the perl prelude have to decide what's valueable and what can be lost during *stringification or interpolation* now, when this language is supposed to live for another 20 years? In Perl5, stringified NVs are only printed to however many digits Perl thinks are worth printing. At the extreme range, it decides to print with scientific notation. That is done for the convenience for interpolation into an output string -- the real decimal representation could be 0.002378462387462341220983458672348961234 I'm not necessarily arguing this is the right or the best dividing line, but I'm saying a line can be drawn if we want. For example: my $color = new HTML::Color(magenta); if $color.as(Str) eq '#FF00FF' and $color eq magenta { $Ashley++; } $color.hex_triplet; # no alpha $color.name; # if we have one... or we can try to make one up (#ff0033 is bluish red ;-) I see no reason why these two should behave in anyway, except that one of them is the canonical format. There is no mnemonic device whatsoever to link interpolation to color naming, and stringification to hexadecimal representation. Why isn't the str method (255,0,255)? Why isn't interpolation more expressive and Dwimmy? I chose this class for expositive purposes as well. It's the canonical representation of a color in HTML -- 6 digit hex. The DWIM factor comes from printing what the object thinks its own value is. A UnixEpochTimestamp thinks of itself as seconds-since-1970. An HTML color thinks of itself as whatever you passed to its constructor, whether that was #A4c or MaGeNtA or #ff say The Unix Epoch Timestamp is $time -- The Unix Epoch Timestamp is 1234567890 say The HTML Color is $color -- The HTML Color is magenta So, to summarize, I want .as(Str) to be the lossless canonical representation, as well as the basis for the default .hash method, while Interpolate would be the pretty-printed localized lossy presentation Role. For localization we need another thing. I propose a new prefix operator, with some funny char we haven't used yet. It would be a part of the Localizable role, and it would return a Str. I'm not attached to the name or the function. I want something for presentation that's different from representation that's different from serialization and I want them to be easy and safe, and I want to know which one will be used to hash my object by default. :) Ashley Winters
matching colors (was Stringification, numification, and booleanification of pairs)
Yuval Kogman skribis 2005-09-25 21:34 (+0300): if $color.as(Str) eq '#FF00FF' and $color eq magenta { $Ashley++; } $color.hex_triplet; # no alpha $color.name; # if we have one... or we can try to make one up (#ff0033 is bluish red ;-) We can do better than equivalence testing for colors. Instead, try to match. Surely a *smart* match operator really is smart? $color ~~ '#FF00FF' == $color ~~ 'magenta' == $color ~~ [ 255, 0, 255 ] Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: Stringification, numification, and booleanification of pairs
Ashley Winters skribis 2005-09-25 12:26 (-0700): It's not a Date, it's a UnixEpochTimestamp. That is precisely the flaw. Are you honestly likely to have that class? If you really need an unix epoch timestamp, wouldn't you just use a very simple integer for that? Because that's what it *is*, by definition. Not an object. And having an epoch timestamp stringify (or interpolate, which as far as I will accept leads to stringification) as anything other than what it is, an integer, is pure nonsense. my Thingy $foo .=from($thing); my Thingy $foo = eval($thing.perl); eval() itself feels like the wrong function for doing this. I'm trying to parse(), not eval(). Neither names are good. Parsing isn't the only thing you want to do, and eval is for executable code that is in a string, not for serialized data. I suggest that we keep data and code separate and use thaw and eval respectively. Also, this means that .perl shouldn't be used for storing objects, at most it should be used for demonstration and debugging. Let's not forget freeze. Objects are both code and data, and thus hard. We may have to consider it all code. say The Unix Epoch Timestamp is $time -- The Unix Epoch Timestamp is 1234567890 I thought you wanted it to interpolate as a well formatted, human-readable date? Don't you mean `~ $time` here? Wow, separating stringification and interpolation really IS confusing! It is NOT TRUE that strings with variables interpolated are always for presentation. It is NOT TRUE that uninterpolated strings are always for storage. Both can be used either way, and in practice are used both ways. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: matching colors (was Stringification, numification, and booleanification of pairs)
On 9/25/05, Juerd [EMAIL PROTECTED] wrote: We can do better than equivalence testing for colors. Instead, try to match. Surely a *smart* match operator really is smart? $color ~~ '#FF00FF' == $color ~~ 'magenta' == $color ~~ [ 255, 0, 255 ] Hmm. That violates my proposal that the right side is the thing that determines how the left side is matched. So there's something wrong with one of the two... If we keep my proposal, then we get: $color ~~ color('#FF00FF') $color ~~ color('magenta') etc., for some definition of color(). In fact, that's probably the right thing to do, is to make color a pattern constructor. Then you can even put it in signatures: sub name(color('#FF00FF')) { magenta } Whatever that buys you If we ditch my proposal, then we can write it as you did. But I feel uncomfortable with that (thus the proposal), since you never know how people may have overloaded ~~ for dwimminess, and when you say: sub print_colored ($color, $text) { $color = do given $color { when 'red' { Color.new('#FF') } when 'green' { Color.new('#00FF00') } when Color { $color } default { fail Unknown color } } } Though in this case it's not much of an issue, unless the red pattern matches /#../ or something, in which case you are losing granularity. I guess the reason it makes me uncomfortable is that old obsession of mine where things that look orthogonal ought to be, like 'red' (a string) and Color (a class). Then again, would one expect: $foo ~~ 'bar' To be equivalent to: ~$foo eq 'bar' Or not? I mean, that can be the string pattern's job, but then 'red' and Color aren't really equivalent anymore. /me punts patterns until he understands more. Luke
Re: Stringification, numification, and booleanification of pairs
* wolverian ([EMAIL PROTECTED]) [050925 11:57]: On Sun, Sep 25, 2005 at 12:52:08PM +0200, Juerd wrote: Hackers on this list, what do you think? I think separating the two is extremely confusing. I do not see any uses for it, but maybe I am not thinking hard enough. Of course, having $thing.'x' produce something else than $thing.'x' is very confusion, however, they have a different purpose: Stringification/Numification should be used to let an object play its natural role within the program. For instance, some Temperature object producing 273 when compared to the melting point of water. Interpolation should be used on places where output is generated, where the outside consumer has less knowledge about the internals. Like 273'C for the same Temperature object. Sorry, my program uses Celcius ;-) I like to have this behavior. The question is: will the two different uses be visible enough that the average programmer will understand it after a while, or will this become one of those nasty dark corners of the language which no-one dares to touch? The more constructs (like pairs, junctions, and hashes) produce different results for both cases, the better the choice for distinction is, because people get aware of it without reading a book. -- MarkOv Mark Overmeer MScMARKOV Solutions [EMAIL PROTECTED] [EMAIL PROTECTED] http://Mark.Overmeer.net http://solutions.overmeer.net
Re: Stringification, numification, and booleanification of pairs
Mark Overmeer skribis 2005-09-25 17:28 (+0200): Stringification/Numification should be used to let an object play its natural role within the program. Agreed, but... For instance, some Temperature object producing 273 when compared to the melting point of water. That's for numeric context, in which it will do this. It doesn't say much (or anything) about strings. For a temperature, it happens to make sense to use the number for stringification as well, because we humans are used to numbers for temperatures. I think more abstract types are more interesting, when it comes to how they behave as strings and in string literals (which I think should be exactly the same). I think that indeed arrays, hashes and pairs are great objects of this discussion. Pairs in much lesser extent, because what they should do in any scalar context is still under discussion: evaluate to the .value, propagating context, or evaluate to something that has to do with the pair itself. For the record, I prefer the latter, for several reasons. Arrays and hashes as numbers evaluate to their number of elements. This is terribly useful. Arrays and hashes as further unspecified scalars evaluate to references to themselves. This too is very useful indeed, especially because we also have automatic dereferencing nowadays. In string context, an array evaluates to its stringified elements joined by whitespace. This is possibly lossy, because the elements may contain spaces as well. It doesn't make sense to me to make it behave any differently in string context than in interpolation. Or, as I really do prefer to put it: to have items in non-string context when they're interpolated. A part of a string is a string, and we shouldn't differentiate between it being part of a string that was built in pieces and it being part of a string that was built as a whole, a string literal. Interpolation should be used on places where output is generated, where the outside consumer has less knowledge about the internals. Like 273'C for the same Temperature object. Sorry, my program uses Celcius ;-) Sure, including the unit does make sense. Still, how you built the complete string for the end user shouldn't determine how the object is stringified. Whether I use say t= ~ $temperature; or say t=, $temperature; or say t=$temperature; it is all presentation to the human. I don't want to be told that for telling things to humans, I must use interpolation. Mostly, because most of the time I don't (I pass the value to a templating thing (and I don't want to have to care about HOW that uses the value later on), and often I use printf). I like to have this behavior. You're not commenting on the difference between using it as a string and using it as an interpolated value, though. Your example compares numeric use to string use, and indeed those should be different. This thread is about strings only, and would your temperature ever make sense as both one form of string and another? In other words, what would say $temp; print, and what would say $temp; print instead? And to conclude it, what would you want say get_temperature(); to print? Are you willing to have this big difference between this and say { get_temperature() }; (Still assuming we won't have auto freezing and auto thawing in much the same way we will have auto referencing and auto dereferencing, because I'd like those operations to be very clear and explicit.) The more constructs (like pairs, junctions, and hashes) produce different results for both cases, the better the choice for distinction is, because people get aware of it without reading a book. Yes, if things are different, they should be really different. For this reason I want ~$foo and +$foo be different where something making sense can be thought of and implemented without much effort, and pairs to evaluate to something OTHER than their values (they're not aliases, and this is most evident with \$pair, which shouldn't be in any way like \$pair.value, and in $pair, which shouldn't be in any way different from ~$pair.) Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
numification and stringification of objects
Whenever possible, object should have useful numeric and string representations. These are generally lossy, but this is not a problem, because a scalar stays a scalar even after being used in a certain context, and the object isn't lost. When a protocol or data format that already has a string format is represented as an object, it should of course evaluate to its common string form when used in string context. Good examples of this can be found in the LWP package. Class Num Str HTTP::Headers number of headers Foo: bar{crlf}Bar: baz{crlf} HTTP::Status200 HTTP/1.1 200 OK HTTP::Date universal epochtime Sun, 06 Nov 1994 08:49:37 GMT HTML::Form number of elementsform ../form One must be careful NOT to pick a certain numification or stringification just because a certain number or string found in the object will be useful. For code to be understandable, the numification or stringification must really BE what the object represents. Again, LWP provides good examples. Class Num Str HTTP::Request - GET / HTTP/1.1{crlf}... LWP::UserAgent - - There's no single obvious meaningful number that represents HTTP::Request, but a careless designer could try and guess that people would be interested in the HTTP version number, the number of headers, or the number of bytes in the body. It should therefor produce a warning when it's used in numeric context. What it returns, is mostly irrelevant but I'd go as far as returning a random number, just to avoid that people actually do this. (This is no problem. Compare it to Perl 5's habit of returning the memory address.) There is, however, a good string representation of an HTTP message. Whether or not this includes the body is irrelevant at this point, but if it's know, it probably should. It can hopefully do so lazily. An UserAgent object has no single obvious meaningful number that it represents, and it's hard to express a machine as a string too. Still, someone who feels a need to use every feature that Perl provides, might use the number of requests and the last requested URL, thinking these would be very popular. In a good design, it shouldn't be a number or a string at all, because it would lead to non-obvious code and would require a comment or diving into documentation, and then an explicit method name serves both ease of programming and readability much better. However, I do think there should be some kind of useful stringification for ALL objects, because objects are often printed for debugging purposes. But I suggest that this be a global method that all objects implicitly inherit from, and not be defined in the object itself. This helps to make all these stringified-for-debugging strings look the same (one programmer could for example perhaps implement a coloured scheme) and to enable us to make using them fatal. Because every object may have its own attributes or even other calculations that will be useful for debugging, there must be a way to specify which ones are used. I think a simple method that returns a string is most appropriate. One example of what this debugging output could be is: { LWP::UserAgent(aen3kx) } aen3kx being the id of the object, and {} being simple delimiters to visually group. Another example, this time with some attributes that a certain method in LWP::UserAgent told Perl to use: { LWP::UserAgent(c23hee) libwww-perl/6.00; 200 } Or, for example a database connection object: { DBI(938eo) connected; dbi:SQLite:foo.db; in transaction } But, as arrays do have a useful way to be represented as a string: element1 element2 element3 and not { Array(123abc) }. It's all very Perl 5-y, and that's because that is a good way to do it: the default is useful for debugging, but you can specify different stringification in case there's an obvious way to stringify. It just gets much less scary to actually do override stringification. In any case, I do think that everything should be explicitly fetchable as well as implicitly. This means that I want .as_html, and not just the HTML::Element in string context. The debugging info mentioned above could be .as_debug, for example, and then we could get { Array(123abc) 0..15 contiguous } from an Array object. I personally like to work without the as_ prefix, so that I get .celcius and .html instead of .as_celcius and .as_html. Always, string context should be primarily concerned with use, not debugging or storage (serialization). Whether this use is for presentation to the user, sending over a wire or storage, the object can't and shouldn't know. It should have one that is most important and very obviously connected to the object, and that one should be used in all stringification. Most objects won't ever need to be presented to the user, and others won't be part of a protocol. In fact, I
Re: Stringification, numification, and booleanification of pairs
In a private conversation with Larry this afternoon, he said that by default $foo and ~$foo and $foo.as(Str) all give the same result (assuming scalar context, etc.). And that @foo[] and [EMAIL PROTECTED] and @foo.as(Str) are the same as join(' ', @foo) where join is effectively: sub join(Str $x is rw, @A) { my Str $y = ''; for $z - (@A) { $y ~= ~$z; } continue { $y ~= $x: } return $y; } Also that a pair ($x = $y) stringifies to $x\t$y and that [EMAIL PROTECTED] for an array of pairs is the same as join(\n, @A); It is also intended that .as(Str, ...) takes extra named args (names TDB) for things like separators and sprintf like format strings so you can customize it, including ways to change the defaults for a class (like the separator for arrays of pairs being \n instead of ' '). -- [EMAIL PROTECTED] [EMAIL PROTECTED]