> I once counted there were about 8000 uses of <type>,error as
> return types for functions in $GOROOT/src which could benefit
> from sum types.

I'm not entirely convinced that sum types are a net win as a
substitute for (T, error) return values.

Where currently we have:

      f, err := os.Open(filename)
      if err != nil {
          return err
      }
      // use f

we'd have to do something like:

      fOrError := os.Open(filename)
      if err, ok := fOrError.(error); ok {
           // ... but what happens if we want to return a distinct
           // value that implements error?
           return err
      }
      f := fOrError.(*os.File)
      // use f

or perhaps:

      var f *os.File
      switch fOrError := os.Open(filename).(type) {
      case *os.File:
          f = fOrError
      case error:
          return fOrError
      }
      // use f

or even, defensively (perhaps os.Open's type might change to admit
more possibilities:

      var f *os.File
      switch fOrError := os.Open(filename).(type) {
      case *os.File:
          f = fOrError
      case error:
          return fOrError
      default:
          panic("unexpected type %T returned from os.Open", fOrError)
          // or return error
      }
      // use f

I don't know about you, but I wouldn't consider any of those a
particular improvement on the current idiom. They're all more verbose
and not actually that much more type-safe.

That doesn't mean that I don't think sum types are a decent idea, but
just that I'm not sure that they're as clear a win for this (a
commonly cited use case) as one might think.

  cheers,
    rog.


On 24 February 2018 at 01:23, Bakul Shah <ba...@bitblocks.com> wrote:
> On Thu, 22 Feb 2018 12:55:01 +0000 Jesper Louis Andersen 
> <jesper.louis.ander...@gmail.com> wrote:
>>
>> For sums, in Go, I have to return a pair,
>>
>> x, err := someOperation(..)
>>
>> but this is slightly inconsistent, insofar I can return "nil, nil", which
>> might not be a valid value, or I can return "3, Error(..)" but in that case
>> the 3 is not to be used. Only one "side" is valid at a given point in time.
>> If you have sum-types in the usual sense, you can define something along
>> the lines of (OCaml follows):
>>
>> type ('a, 'b) result = Ok of 'a | Error of 'b
>
> I once worked out some details of adding sum types to Go and I
> think it is quite doable and easy to implement. For example,
>
>     func f(i int) float64|error {
>         if i == 0 { return errors.New("not zero") }
>         return 1./float64(i)
>     }
>
> As in OCaml "|" is used for sum types and it binds less
> tightly than existing type "expressions".
>
>> And then you can discriminate on this value via pattern matching
>>
>> match res with
>> | Ok value -> ...
>> | Error err -> ...
>
> Not quite the same but something similar is doable with
> type switch.
>
>     res := f(j)
>     switch res.(type) {
>     case error: ...
>     case string: ...
>     }
>
> This use is identical with f returning interface{} (even the f
> body remains exactly the same).  This makes sense since
> interface{} is in a sense the sum of all other types.
>
> But by allowing sum type, we can do better checking within f
> (e.g. return "string" will fail to compile). And by using a
> sum type instead of a product type to return a value or error
> also makes the code clearer.
>
> I once counted there were about 8000 uses of <type>,error as
> return types for functions in $GOROOT/src which could benefit
> from sum types. Now there seem to be about 4253 instances
> (found using a crude regexp).
>
> I think I worked out the semantics of T1|T2 where T1 and T2
> are both interface types themselves. It all seem to fit
> together, at least on paper! I need to find my notes....
>
>> The other matching construction is a switch-statement, but such a statement
>> doesn't allow for matching deeply into an AST structure, which a
>> traditional pattern matcher does.
>
> Deeper matching also binds names to matched parts. e.g.
>
>     sumsqr [] = 0
>     sumsqr (x:xs) = x*x + sumsqr xs
>
> This sort of binding may be difficult to shoehorn into Go.
> There may be no real benefit of binding head, tail of a slide
> but consider an AST. If you are already cracking it open for
> matching it with a pattern, you may as well bind variables to
> interesting parts.
>
>     match stmt {
>     case If1stmt(test:, thenstmt:): ...
>     case If2stmt(test:, thenstmt:, elsestmt:): ...
>     ...
>     }
>
> Hard to come up with an intuitive syntax here.  Also probably
> impossible  to add func level patterns.
>
>> Coincidentally, given sum-types, you can write a regexp matching engine in
>> very few lines of code. See Bob Harper's "Programming in Standard ML" [2]
>> for example; it is the introductory example to get a feel for the language.
>> The solution uses sum types to define the AST for regular expressions, and
>> then uses pattern matching to build a matcher on regular expressions. I
>> can't remember how far Bob takes the exposition however.
>
> This should be doable given my sum-type proposal sketch above?!
>
>> [0] They are really the same in the right setting. In a boolean algebra,
>> for instance, + is OR and * is AND. If you look at them from the Category
>> Theory branch of mathematics they are related: they are duals of each other
>> which means that if you "invert" one you get the other and vice versa.
>>
>> [1] Obviously, Go, being a descendant of Algol has two syntactic classes:
>> statements and expressions, whereas OCaml is descendant from either Lisp or
>> the Lambda Calculus depending on view. Those languages only have
>> expressions as a syntactic class.
>
> sum-types (which are easy to implement) and pattern matching
> (may be not so easy) can be added to Go even if it has
> non-expression syntatic classes.
>
>> [2] http://www.cs.cmu.edu/~rwh/isml/book.pdf
>>
>> [3]
>> https://www.microsoft.com/en-us/research/wp-content/uploads/1987/01/slpj-book-1987-small.pdf
>
> SLPJ's book was quite an eye opener for me back in the '80s!
>
> --
> You received this message because you are subscribed to the Google Groups 
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to golang-nuts+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to