Re: Exceptuations
On Wed, Oct 05, 2005 at 13:00:55 -0600, Luke Palmer wrote: I don't think it was a how is this possible, but more of a what business does it have?. And as far as I gathered, they're saying pretty much what you've been saying, but in a different way. It's about the continuation boundary; that is, if you're outside a module, you have no say in how the module does its business. You can continue only at the module boundary, replacing a return value from its public interface. As I see it this is the usefulness of exceptions being handled by distant code. The code in the module inverts it's interface by calling code it doesn't know with a certain parameter, accepting a certain parameter back. That way encapsulation is not broken, but errors that happen deep inside a call chain can be dealt with by code that can interact with the user. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me climbs a brick wall with his fingers: neeyah! pgpmp8WUodYYB.pgp Description: PGP signature
Re: Exceptuations
On Wed, Oct 05, 2005 at 13:41:37 -0700, Dave Whipp wrote: Reading this thread, I find myself wondering how a resumable exception differs from a dynamically scropted function. Imagine this code: This is sort of like what I mean, except that there is no encapsulation breakage, since the interface is inverted. The advantage of this approach is that error handling code in a submodule can benefit from generic, reusable exception handling code that is provided by it's caller. temp sub FileNotWriteable( Str $filename ) { With an exception handler and continuable exceptions you don't have to know what the error handler is, or make sure that the module actually throws the error. The exception handler instead deals with the type of the exception in a generic manner (it doesn't care when the exception was actually generated). The module doesn't need to throw the error it just needs to fail (or delegate a fail), until the failure crosses into a 'use fatal' scope. That way both the catching code and the throwing code are reusable and orthogonal when they are unrelated, but the possibility of coupling handling code with throwing code is still there. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me groks YAML like the grasshopper: neeyah!! pgpzo38NCmZ47.pgp Description: PGP signature
Re: zip: stop when and where?
On 10/5/05, Damian Conway [EMAIL PROTECTED] wrote: Luke wrote: I'm just wondering why you feel that we need to be so careful. Because I can think of at least three reasonable and useful default behaviours for zipping lists of differing lengths: # Minimal (stop at first exhausted list)... for @names ¥ @addresses - $name, $addr { ... } # Maximal (insert undefs for exhausted lists)... for @finishers ¥ (10..1 :by(-1)) - $name, $score { $score err next; ... } # Congealed (ignore exhausted lists)... for @queue1 ¥ @queue2 - $server { ... } Which means that there will be people who expect each of those to *be* the default behaviour for unbalanced lists. Perhaps that makes sense. That certainly makes sense for other kinds of constructs. Something makes me think that this is a little different. Whenever somebody asks what Y is on #perl6, and I tell them that it interleaves two lists, a follow-up question is *always* what does it do when the lists are unbalanced. Now, that may just be a behavior of #perl6ers, but I'm extrapolating. It means that there isn't an assumption, and if they weren't #perl6ers, they'd RTFM about it. When I learned Haskell and saw zip, I asked the very same question[1]. I was about as comfortable writing Haskell at that point as beginning programmers are with writing Perl, but it still took me about ten seconds to write a test program to find out. The rest of Perl doesn't trade a reasonable default behavior for an error, even if it *might* be surprising the first time you use it. It doesn't take people long to discover that kind of error and never make that mistake again. If we make zip return a list of tuples rather than an interleaved list, we could eliminate the final 1/3 of those errors above using the typechecker. That would make the for look like this: for @a Y @b - ($a, $b) {...} An important property of that is the well-typedness of the construct. With the current zip semantics: my A @a; my B @b; for @a Y @b - $a, $b { # $a has type A (+) B # $b has type A (+) B } With tuple: my A @a; my B @b; for @a Y @b - ($a, $b) { # $a has type A # $b has type B } Which is more correct. No... it's just correct, no superlative needed. It also keeps things like this from happening: for @a Y @b - $a, $b { say $a ; $b } # a1 b1 # a2 b2 # a3 b3 # ... Oh, I need a count, says the user: for @a Y @b Y 0... - $a, $b { # oops, forgot to add $index say $a ; $b } # a1 b1 # 0 a2 # b2 1 # ... Luke [1] But I didn't need to. The signature told me everything: zip :: [a] - [b] - [(a,b)] It *has* to stop at the shortest one, because it has no idea how to create a b unless I tell it one. If it took the longest, the signature would have looked like: zip :: [a] - [b] - [(Maybe a, Maybe b)] Anyway, that's just more of the usual Haskell praise.
Re: zip: stop when and where?
Luke Palmer wrote: zip :: [a] - [b] - [(a,b)] It *has* to stop at the shortest one, because it has no idea how to create a b unless I tell it one. If it took the longest, the signature would have looked like: zip :: [a] - [b] - [(Maybe a, Maybe b)] Anyway, that's just more of the usual Haskell praise. Given that my idea about using optional binding for look-ahead didn't fly, maybe it would work here, instead: @a Y @b - $a, $b { ... } # stop at end of shortest @a Y @b - $a, ?$b { ... } # keep going until @a is exhaused @a Y @b - ?$a, ?$b { ... } # keep going until both are exhaused I think we still need a way to determine if an optional arg is bound. Can the Cexists function be used for that (if exists $b {...})? Dave.
Re: Exceptuations
On Wed, 5 Oct 2005 19:24:47 +0200, Yuval Kogman wrote: On Wed, Oct 05, 2005 at 16:57:51 +0100, Peter Haworth wrote: On Mon, 26 Sep 2005 20:17:05 +0200, TSa wrote: Piers Cawley wrote: Exactly which exception is continued? The bottommost one. If you want to return to somewhere up its call chain, do: $!.caller(n).continue(42) Whow, how does a higher level exception catcher *in general* know what type it should return and how to construct it? The innocent foo() caller shouldn't bother about a quux() somewhere down the line of command. Much less of its innards. Well said. No! Not well said at all! Sorry, I misread that. I thought I was agreeng with how does a higher level exception catcher know what to change in order to make resuming the continuation useful?, especially in the light of Piers saying that the bottom-most exception should be the one resumed. The highest level exception is the only one a caller has any right to deal with, but even then it doesn't really know what will happen if it resumes some random continuation attached to the exception. CATCH { when some_kind_of_error { $!.continue($appropriate_value_for_some_kind_of_error) } } That just gives me the willies, I'm afraid. -- Peter Haworth [EMAIL PROTECTED] Disconcerting Haworth Fortress Unicycling Melody Gundam -- http://www.channel4.com/4later/bits/manga.html
Re: zip: stop when and where?
On Thu, Oct 06, 2005 at 10:31:50AM -0600, Luke Palmer wrote: If we make zip return a list of tuples rather than an interleaved list, we could eliminate the final 1/3 of those errors above using the typechecker. That would make the for look like this: for @a Y @b - ($a, $b) {...} I like it (I think). I'm not sure about the syntax though. Is this one of those places where round brackets are equivalent to square brackets? I.e., would this be the same: for @a ¥ @b - [$a,$b] { ... } ? Also, it seems like this syntax would almost always require the brackets to be correct. Most of the time people will see and expect for loops that look like this: for MUMBLE - $a, $b { ... } Except now they've probably got a semantic error when MUMBLE contains ¥ or is prefixed by zip. This type of error mayn't be so easy to detect depending on what they're mumbling about. -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: zip: stop when and where?
Dave Whipp skribis 2005-10-06 9:57 (-0700): Given that my idea about using optional binding for look-ahead didn't fly, maybe it would work here, instead: @a Y @b - $a, $b { ... } # stop at end of shortest @a Y @b - $a, ?$b { ... } # keep going until @a is exhaused @a Y @b - ?$a, ?$b { ... } # keep going until both are exhaused I think we still need a way to determine if an optional arg is bound. Can the Cexists function be used for that (if exists $b {...})? Y isn't something that is specific to for loops, or to sub invocation, so this cannot be a solution. Also remember that Y creates a single flattened list by definition, and that the given sub's arity determines how many items of that list are used. It's perfectly legal and possibly even useful to say for @foo, @bar, @baz - $quux, $xyzzy { ... } And even though for @foo Y @bar Y @baz - $quux, $xyzzy { ... } is something you will probably not see very often, it's still legal Perl, even though it looks asymmetric. This too makes finding the solution in arguments a non-solution. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: zip: stop when and where?
On 10/6/05, Juerd [EMAIL PROTECTED] wrote: for @foo Y @bar Y @baz - $quux, $xyzzy { ... } is something you will probably not see very often, it's still legal Perl, even though it looks asymmetric. This too makes finding the solution in arguments a non-solution. Don't be silly. There's no reason we can't break that; it's not an idiom anybody is counting on. If you still want the behavior: for flatten(@foo Y @bar Y @baz) - $quux, $xyzzy {...} But your point about Y returning a list and therefore not being for-specific is quite valid. Luke
$value but lexically ...
Cbut properties get attached to a value, and are available when the value is passed to other functions/ etc. I would like to be able to define a property of a value that is trapped in the lexical scope where it is defined. The example that set me thinking down this path is sub foo( $a, ?$b = rand but :is_default ) { ... bar($a,$b); } sub bar( $a, ?$b = rand but :is_default ) { warn defaulting \$b = $b if $b.is_default; ... } It would be unfortunate if the is_default property attached in foo triggers the warning in bar. So I'd like to say somthing like sub foo( $a, ?$b = 0 but lexically :is_default ) {...} or sub foo( $a, ?$b = 0 but locally :is_default ) {...} to specify that I don't want the property to the propagated.
Re: Exceptuations
On Thu, Oct 06, 2005 at 18:11:38 +0100, Peter Haworth wrote: The highest level exception is the only one a caller has any right to deal with, but even then it doesn't really know what will happen if it resumes some random continuation attached to the exception. But then we gain nothing CATCH { when some_kind_of_error { $!.continue($appropriate_value_for_some_kind_of_error) } } That just gives me the willies, I'm afraid. Why? when i can't open a file and $! tells me why i couldn't open, i can resume with an alternative handle that is supposed to be the same when I can't reach a host I ask a user if they want to wait any longer when disk is full I ask the user if they want to write somewhere else when a file is unreadable i give the user the option to skip These handlers are progressively more knowlegable of the code they're dealing with, but they don't touch the actual guts - that's the whole merit of continuable exception, because otherwise you might aswell just start over. These are 100% reusable in the first exception handler, and not reusable but still applicable to an opaque call at the last handler. It doesn't matter who opens the file file, the exception handler will produce the same effect but in a different way. CATCH { when Error::IO::... { open ... } when MyApp::Timeout { ask_user_to_continue_or_abort(); } ... } -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me dodges cabbages like macalypse log N: neeyah! pgpQfW4BcQBM2.pgp Description: PGP signature
Re: $value but lexically ...
On 10/6/05, Dave Whipp [EMAIL PROTECTED] wrote: sub foo( $a, ?$b = rand but :is_default ) { ... bar($a,$b); } sub bar( $a, ?$b = rand but :is_default ) { warn defaulting \$b = $b if $b.is_default; ... } It would be unfortunate if the is_default property attached in foo triggers the warning in bar. So I'd like to say somthing like sub foo( $a, ?$b = 0 but lexically :is_default ) {...} or sub foo( $a, ?$b = 0 but locally :is_default ) {...} to specify that I don't want the property to the propagated. This came up before when I proposed lexical properties. That was before we knew that a property was just a role. So you can do a lexical property like so: { my role is_default {} # empty sub foo($a, ?$b = 0 but is_default) {...} } { my role is_default {} sub bar($a, ?$b = rand but is_default) {...} } If this turns out to be a common want, I can see: sub bar($a, ?$b = rand but my $is_default) { warn Defaulted to $b if $b.does($is_default); } But I don't think it will be, and the empty role is easy enough. Luke
Re: Exceptuations
On 10/6/05, Yuval Kogman [EMAIL PROTECTED] wrote: when i can't open a file and $! tells me why i couldn't open, i can resume with an alternative handle that is supposed to be the same when I can't reach a host I ask a user if they want to wait any longer when disk is full I ask the user if they want to write somewhere else when a file is unreadable i give the user the option to skip I'm not bashing your idea, because I think it has uses. But I'll point out that all of these can be easily accompilshed by writing a wrapper for open(). That would be the usual way to abstract this kind of thing. Luke
Re: $value but lexically ...
Luke Palmer skribis 2005-10-06 14:23 (-0600): my role is_default {} # empty sub foo($a, ?$b = 0 but is_default) {...} Would this work too? 0 but role {} Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: $value but lexically ...
On 10/6/05, Juerd [EMAIL PROTECTED] wrote: Luke Palmer skribis 2005-10-06 14:23 (-0600): my role is_default {} # empty sub foo($a, ?$b = 0 but is_default) {...} Would this work too? 0 but role {} Most certainly, but you would have no way to refer to that role later, so it is questionable how useful that construct is. No, it's not questionable. That is a useless construct. Luke
Type annotations
Autrijus convinced me that we have to really nail down the semantics of type annotation without use static. Let's first nail down what I meant by semantics in that sentence. Basically, when do various things get checked? Run time or compile time (not coercion; I have a proposal for that coming). Oh, I'm asking p6l here, not Larry in particular. This part of the language is yet-undesigned, so some arguments one way or the other would be nice to hear. So we're in line one of a Perl program, with static typing/inference disabled (or at least inference *checking* disabled; perl may still use it for optimization). When do the following die: compile time (which includes CHECK time), run time, or never? my Array $a = 97; # dies eventually, but when? my Int $b = 3.1415; # dies at all? sub foo (Int $arg) {...} foo(hello); # should die at the latest when foo() is called sub bar (Int $arg -- Str) {...} foo(bar(42)); sub static (Code $code, Array $elems -- Array) { [ $elems.map:{ $code($_) } ] } sub dynamic ($code, $elems) { [ $elems.map:{ $code($_) } ] } static({ $_+1 }, dynamic(notcode, [1,2,3,4,5])); dynamic(notcode, static({ $_+1 }, [1,2,3,4,5])); That should cover most of the interesting cases. Luke
Re: Type annotations
On Thu, Oct 06, 2005 at 17:44:10 -0600, Luke Palmer wrote: Autrijus convinced me that we have to really nail down the semantics of type annotation without use static. Let's first nail down what I meant by semantics in that sentence. Basically, when do various things get checked? Run time or compile time (not coercion; I have a proposal for that coming). Oh, I'm asking p6l here, not Larry in particular. This part of the language is yet-undesigned, so some arguments one way or the other would be nice to hear. So we're in line one of a Perl program, with static typing/inference disabled (or at least inference *checking* disabled; perl may still use it for optimization). When do the following die: compile time (which includes CHECK time), run time, or never? my Array $a = 97; # dies eventually, but when? my Int $b = 3.1415; # dies at all? Both die at compile time, because the user explicitly contradicted him/herself. This is like saying my int = $x :: float; since they're constants and their types are very well known. sub foo (Int $arg) {...} foo(hello); # should die at the latest when foo() is called Immediately, at compile time, for every caller of foo unless 'no static' or whatever is active for that scope. However, no inferencing is made - this is just 1 level deep. sub bar (Int $arg -- Str) {...} foo(bar(42)); Since -- is explicit I'm not sure if it means infer this even if we're not globally inferring. I lean towards compile time error here since I think it would be nice to have that, but there are some disadvantages. Perhaps this should infer only in the lexical scope that 'sub bar' was defined in, to make sure that error reporting does not confuse naive users of the module that defines foo, without asking for compile time inference. sub static (Code $code, Array $elems -- Array) { [ $elems.map:{ $code($_) } ] } sub dynamic ($code, $elems) { [ $elems.map:{ $code($_) } ] } static({ $_+1 }, dynamic(notcode, [1,2,3,4,5])); dynamic(notcode, static({ $_+1 }, [1,2,3,4,5])); This is only with full inferencing, either lexically enabled as a a pragma (in the scope that invokes), or if enabled globally. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me does a karate-chop-flip: neeyah!! pgpZ0kQYyANwT.pgp Description: PGP signature
Re: Exceptuations
On Thu, Oct 06, 2005 at 14:27:30 -0600, Luke Palmer wrote: On 10/6/05, Yuval Kogman [EMAIL PROTECTED] wrote: when i can't open a file and $! tells me why i couldn't open, i can resume with an alternative handle that is supposed to be the same when I can't reach a host I ask a user if they want to wait any longer when disk is full I ask the user if they want to write somewhere else when a file is unreadable i give the user the option to skip I'm not bashing your idea, because I think it has uses. But I'll point out that all of these can be easily accompilshed by writing a wrapper for open(). That would be the usual way to abstract this kind of thing. Stylistically I would tend to disagree, actually. I think it's cleaner to use exception handling for this. Also, this implies that you know that the errors are generated by open. This is OK for open(), but if the errors are generated from a number of variants (MyApp::Timeout could come from anywhere in a moderately sized MyApp), then wrapping is not really an option. -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me groks YAML like the grasshopper: neeyah!! pgppFkb4LL0f1.pgp Description: PGP signature
Re: Type annotations
On 10/6/05, Luke Palmer [EMAIL PROTECTED] wrote: So we're in line one of a Perl program, with static typing/inference disabled (or at least inference *checking* disabled; perl may still use it for optimization). When do the following die: compile time (which includes CHECK time), run time, or never? This is just my opinions as a Perl programmer in the trenches. I would expect Typed variables to auto-coerce themselves, but not impose fatality. Predictable auto-coercion would be nifty in quick-and-dirty programs. Ignore my advice at will -- nobody's required to use Types in their own code, so there's no need for them to be universally valuable. However, since I expect builtins and all standard functions to have fully declared Type signatures, consider how these decisions would affect _every_ program, before ordering the summary execution of everyone's poor little Perl script. my Array $a = 97; # dies eventually, but when? Runtime -- cannot coerce Int value to Array my Int $b = 3.1415; # dies at all? Doesn't die, $b == 3. Int scalars should coerce anything which can be prefix:+'d. sub foo (Int $arg) {...} foo(hello); # should die at the latest when foo() is called $arg should be undef but Exception::InvalidInteger(Str value 'hello' cannot be coerced to an Int at $?LINE) sub bar (Int $arg -- Str) {...} foo(bar(42)); If bar returns a Str ~~ /Perl6::Grammar::Int/, it gets coerced; otherwise, undef but Exception sub static (Code $code, Array $elems -- Array) { [ $elems.map:{ $code($_) } ] } sub dynamic ($code, $elems) { [ $elems.map:{ $code($_) } ] } static({ $_+1 }, dynamic(notcode, [1,2,3,4,5])); die Str value 'notcode' cannot be called as a Sub reference -- have you asked Larry how to make a symbolic function call, lately?; dynamic(notcode, static({ $_+1 }, [1,2,3,4,5])); Same. Just my 2¢ Ashley Winters
Re: Exceptuations
Peter Haworth [EMAIL PROTECTED] writes: On Wed, 5 Oct 2005 19:24:47 +0200, Yuval Kogman wrote: On Wed, Oct 05, 2005 at 16:57:51 +0100, Peter Haworth wrote: On Mon, 26 Sep 2005 20:17:05 +0200, TSa wrote: Piers Cawley wrote: Exactly which exception is continued? The bottommost one. If you want to return to somewhere up its call chain, do: $!.caller(n).continue(42) Whow, how does a higher level exception catcher *in general* know what type it should return and how to construct it? The innocent foo() caller shouldn't bother about a quux() somewhere down the line of command. Much less of its innards. Well said. No! Not well said at all! Sorry, I misread that. I thought I was agreeng with how does a higher level exception catcher know what to change in order to make resuming the continuation useful?, especially in the light of Piers saying that the bottom-most exception should be the one resumed. I'm sorry, we appear to have lost some kind of context, the original example given only had one exception thrown, but it got propagated up through a long call chain. At no point did anything catch the original exception and rethrow. If they had, you're absolutely correct in asserting that by default things should resume from the point of the outermost rethrow. A brave exception catcher (or more likely programmer with a debugger) might want to crack that exception open and examine its inner exceptions, but in general that's not going to be safe. The scary syntax proposed above is, again, the sort of thing that might be useful in a debugger I don't really care about the inner workings of these helper functions, I just want 'open' to return this mocked handle. (actually in that case, being able to do $!.caller(open).continue(MockIO.new), where 'caller open' looks up the call chain for the lowest call to open and returns that continuation would be rather neat) The highest level exception is the only one a caller has any right to deal with, but even then it doesn't really know what will happen if it resumes some random continuation attached to the exception. Oh stop with the 'rights'. And it's not dealing with a 'random' continuation, if it's going to resume it should be damned careful about which exceptions it resumes from; you don't just go around doing CATCH {...; $!.continue(...)}, you do CATCH SomeSpecificKindOfResumableException { ...; $!.continue(...)}. And, in general, you don't do that either, because in the average program you catch the exception at a point where you can simply return a sensible default to your caller. Resumable exceptions come into their own, however, when you're debugging. I can envisage doing: perl6 -debug::on::error some_script And have it run along happily until an exception gets propagated up to the top level, at which point the debugger swings into action and uses the continuation to tunnel back to the point at which the exception was thrown so the programmer can inspect the program state, possibly fix things up, return something sensible and carry on. CATCH { when some_kind_of_error { $!.continue($appropriate_value_for_some_kind_of_error) } } That just gives me the willies, I'm afraid. It doesn't amuse me that much, unless whatever generates $appropriate_value_for_some_kind_of_error is very, very smart indeed. But, as I've said above, that's not really where resumable exceptions shine. -- Piers Cawley [EMAIL PROTECTED] http://www.bofh.org.uk/