July 20, 2014
On 07/19/2014 08:37 PM, Andrei Alexandrescu wrote:
> On 7/16/14, 3:22 AM, bearophile wrote:
>> Andrei Alexandrescu:
>>> http://www.reddit.com/r/programming/comments/2aruaf/dconf_2014_keynote_high_performance_code_using_d/
>>>
>>>
>>
>> Despite Walter is used to "pipeline programming", so the next step is to also handle failures and off-band messages in a functional way (without exceptions and global error values) with two "parallel pipelines", here named "Railway-Oriented Programming". This is one of the simplest introductions (and he can skip the slides 19-53) that I have found of this topic (that in the Haskell community is explained on the base of monads):
>>
>> http://www.slideshare.net/ScottWlaschin/railway-oriented-programming
> 
> Just read the slides, very interesting.
(...)

Didn't look at the slides, but I remember finding the following article a very nice introduction: http://fsharpforfunandprofit.com/posts/recipe-part2/

(...)
July 20, 2014
Andrei Alexandrescu:

> Just read the slides, very interesting.

There are many papers, books and articles around that explain the same things, but that explanation is easy to understand even for people not used to functional programming (as I still partially am).


> I think it would be interesting to experiment with an Expected!T that holds an Algebraic!(T, Exception) as state,

In those slides as other member of the sum type they have used an enumeration of possible error conditions (or at first even just strings of the error messages), sometimes augmented with more information, like:

| EmailNotValid of EmailAddress
| DbAuthorizationError of ConnectionString * Credentials
| SmtpTimeout of SmtpConnection
| SmtpBadRecipient of EmailAddress


> template bind(alias fun) { ... }
>
> such that given a function e.g.
>
> int fun(string a, double b);
>
> bind!fun is this function:
>
> Expected!int bind!fun(Expected!string a, Expected!double b) {
>   if (a.sux || b.sux) return composeExceptions(a, b);
>   return fun(a.rox, b.rox);
> }
>
> There would also be bindNothrow:
>
> Expected!int bindNothrow!fun(Expected!string a, Expected!double b) {
>   if (a.sux || b.sux) return composeExceptions(a, b);
>   try return fun(a.rox, b.rox);
>   catch (Exception e) return e;
> }

One of the main points of using those two railways is to avoid exceptions.


>> but of course built-in tuple syntax and basic forms of pattern matching
>> in switch (https://d.puremagic.com/issues/show_bug.cgi?id=596 ) improve
>> the syntax and make the code more handy, handy enough to push more D
>> programmers in using it.
>
> No :o).

Are you saying you don't want built-in tuples and that you also don't agree with the proposal in issue 596 and that you don't agree that a better syntax doesn't make monads like those actually handy to use? I don't understand what's controversial in what I have written there.

From a syntax point of view issue 596 asks for an optional onMatch method, and if you want a syntax to create variables in switch cases. Plus support for structs and classes as variables to switch on.

The use of Algebraic, Nullable and Expected is very different (and safer) if you use them through pattern matching. The point is not to ape the functional languages: currently in D Nullable is not much safer (and not more handy) than using a null pointer.

Bye,
bearophile
July 20, 2014
On 7/20/14, 5:57 AM, bearophile wrote:
> In those slides as other member of the sum type they have used an
> enumeration of possible error conditions (or at first even just strings
> of the error messages), sometimes augmented with more information, like:
>
> | EmailNotValid of EmailAddress
> | DbAuthorizationError of ConnectionString * Credentials
> | SmtpTimeout of SmtpConnection
> | SmtpBadRecipient of EmailAddress


No, those would be stored with the exception (possibly as part of its dynamic type). That's the obvious way to achieve that in D; we don't want to copy verbatim what's most appropriate for other languages.

>> template bind(alias fun) { ... }
>>
>> such that given a function e.g.
>>
>> int fun(string a, double b);
>>
>> bind!fun is this function:
>>
>> Expected!int bind!fun(Expected!string a, Expected!double b) {
>>   if (a.sux || b.sux) return composeExceptions(a, b);
>>   return fun(a.rox, b.rox);
>> }
>>
>> There would also be bindNothrow:
>>
>> Expected!int bindNothrow!fun(Expected!string a, Expected!double b) {
>>   if (a.sux || b.sux) return composeExceptions(a, b);
>>   try return fun(a.rox, b.rox);
>>   catch (Exception e) return e;
>> }
>
> One of the main points of using those two railways is to avoid exceptions.

Avoid exceptions as control flow, not as means of passing error information around. I think D's exception chains are very good at the latter. We should use them.


Andrei
July 22, 2014
On Wednesday, 16 July 2014 at 10:22:41 UTC, bearophile wrote:
> Andrei Alexandrescu:
>> http://www.reddit.com/r/programming/comments/2aruaf/dconf_2014_keynote_high_performance_code_using_d/
>
> Despite Walter is used to "pipeline programming", so the next step is to also handle failures and off-band messages in a functional way (without exceptions and global error values) with two "parallel pipelines", here named "Railway-Oriented Programming". This is one of the simplest introductions (and he can skip the slides 19-53) that I have found of this topic (that in the Haskell community is explained on the base of monads):
>
> http://www.slideshare.net/ScottWlaschin/railway-oriented-programming
>
> In Bugzilla there are already requests for some Railway-Oriented Programming:
>
> https://issues.dlang.org/show_bug.cgi?id=6840
> https://issues.dlang.org/show_bug.cgi?id=6843
>
> I think no language extensions are needed for such kind of programming, but of course built-in tuple syntax and basic forms of pattern matching in switch (https://d.puremagic.com/issues/show_bug.cgi?id=596 ) improve the syntax and make the code more handy, handy enough to push more D programmers in using it.
>
> For some examples of those things in a system language, this page shows some little examples of functional syntax for Rust:
> http://science.raphael.poss.name/rust-for-functional-programmers.html
>
> Bye,
> bearophile

I think that approach is more convincing for functional languages than for D, especially if you are limited to a single return type.

Why not just follow the use Unix stdout/stderr model, and provide an OutputRange for errors to be sent to?

I don't really believe that there are two 'railway tracks' in the sense that that presentation implies. Once an error has occurred, typically not much more pipeline processing happens. As for Unix, stdout from one step is tied to stdin, but stderr is output only. There may be further processing of the stderr stream (eg, errors may be reported to a database), but the steps are completely independent from the main stdin-stdout track. I think you get a messy design if you try to combine both into a single pipeline.

I think it could be quite interesting to see which algorithms can be created with an Error OutputRange model.
July 22, 2014
On 7/22/14, 3:03 AM, Don wrote:
> I don't really believe that there are two 'railway tracks' in the sense
> that that presentation implies. Once an error has occurred, typically
> not much more pipeline processing happens. As for Unix, stdout from one
> step is tied to stdin, but stderr is output only. There may be further
> processing of the stderr stream (eg, errors may be reported to a
> database), but the steps are completely independent from the main
> stdin-stdout track. I think you get a messy design if you try to combine
> both into a single pipeline.

The nice thing is that once the red track is taken, things go through the other functions (which weren't written to take care of errorneous inputs) automatically at a small syntactic cost (the "<>>" operator). -- Andrei

July 22, 2014
On 7/22/14, 3:03 AM, Don wrote:
> I don't really believe that there are two 'railway tracks' in the sense
> that that presentation implies. Once an error has occurred, typically
> not much more pipeline processing happens. As for Unix, stdout from one
> step is tied to stdin, but stderr is output only. There may be further
> processing of the stderr stream (eg, errors may be reported to a
> database), but the steps are completely independent from the main
> stdin-stdout track. I think you get a messy design if you try to combine
> both into a single pipeline.

The nice thing is that once the red track is taken, things go through the other functions (which weren't written to take care of errorneous inputs) automatically at a small syntactic cost (the ">>" operator). -- Andrei

July 22, 2014
Don:

>I think that approach is more convincing for functional languages than for D, especially if you are limited to a single return type.<

Hopefully someday we'll have good enough tuples in D (including their destructuring), this is similar to having multiple return values.

Bye,
bearophile
1 2 3
Next ›   Last »