Re: [go-nuts] Appreciating Go

2018-02-25 Thread Maxim Ivanov


> That's why I've used *time.Time, not time.Time - if you try to use it when 
> t.Err is set you'll get panic because of nil value. 
>
>
>
Runtime checks doesn't count :) Compiler still allowed you to use value, 
when error was set. 

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-25 Thread Alex Efros
Hi!

On Sun, Feb 25, 2018 at 01:51:08AM -0800, Maxim Ivanov wrote:
> > type Time struct { 
> > Err error 
> > *time.Time 
> > } 
> Problem is that it continues to be product type, nothing really enforces 
> that you can't use t as a time.Time when t.Err is set. 

That's why I've used *time.Time, not time.Time - if you try to use it when
t.Err is set you'll get panic because of nil value.

-- 
WBR, Alex.

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-25 Thread roger peppe
On 24 February 2018 at 22:02, Bakul Shah  wrote:
> r := os.Open(filename)
> if isError(r) { return r.(error) }
> f := r.(*os.File) // or better: var f *os.File; f = r

I don't think the "or better" alternative would be possible. The of r
is still `*os.File|error`, not *os.File, and this not assignable to a
*os.File without some kind of type assertion. Unless somehow isError
is a special language builtin that manages to change the type of r
after calling it. I can't see how that would work though.

So here we've got two type assertions, both of which can potentially
panic. At least, I always look very carefully at type assertions
without a `, ok` clause because the consequences are so bad if you get
them wrong.

> Error checking being a common pattern, isError() can be added as a builtin
> or trivially in errors pkg. Likely the enclosing function also returns an 
> error
> so the return in the second line above can be just return r but with the
> current product type approach you’d have return nil, err.

That's only the case if you're returning exactly the same type.

> You are only looking at code after returning. Code within a function benefits
> more (gets simplified).
>
> func f(s string) (int|error) { // instead of (int,error)
>   ...
>   return err // instead of return 0,err
>   ...
>   return 1 // instead of return 1,nil
>   // and return n, err case disappears
>
> Having to return an extra thing that gets discarded right away is annoying.

It's perhaps a little annoying (although it would be less annoying if
we had a standard identifier for "zero value - see
https://github.com/golang/go/issues/19642), but AFAICS using sum types
instead would end up more annoying in practice. Also, it's not *that*
uncommon to need to return both a valid value and an error.

  cheers,
rog.

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-25 Thread Maxim Ivanov


> Short version to just get a taste: 
>
> type Time struct { 
> Err error 
> *time.Time 
> } 
>  
> func now(pass bool) Time { 
> if !pass { 
> return Time{Err: errors.New("not now")} 
> } 
> now := time.Now() 
> return Time{Time: &now} 
> } 
>  
> t := now(…) 
> f t.Err != nil { 
> return t.Err 
> } 
>
>
Problem is that it continues to be product type, nothing really enforces 
that you can't use t as a time.Time when t.Err is set. 

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-25 Thread Alex Efros
Hi!

On Sat, Feb 24, 2018 at 02:02:37PM -0800, Bakul Shah wrote:
> r := os.Open(filename)
> if isError(r) { return r.(error) }
> f := r.(*os.File) // or better: var f *os.File; f = r
> 
> Error checking being a common pattern, isError() can be added as a builtin
> or trivially in errors pkg. Likely the enclosing function also returns an 
> error
> so the return in the second line above can be just return r but with the
> current product type approach you’d have return nil, err.
> 
> You are only looking at code after returning. Code within a function benefits
> more (gets simplified).
> 
> func f(s string) (int|error) { // instead of (int,error)
>   ...
>   return err // instead of return 0,err
>   ...
>   return 1 // instead of return 1,nil
>   // and return n, err case disappears

Actually you can have such a sum type right now, without any changes to
syntax or stdlib, and with much more pleasant usage syntax.

Full example: https://play.golang.org/p/tVSAqRprmKI

Short version to just get a taste:

type Time struct {
Err error
*time.Time
}

func now(pass bool) Time {
if !pass {
return Time{Err: errors.New("not now")}
}
now := time.Now()
return Time{Time: &now}
}

t := now(…)
f t.Err != nil {
return t.Err
}
// Use t just like time.Time.

-- 
WBR, Alex.

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-25 Thread 'Axel Wagner' via golang-nuts
On Sat, Feb 24, 2018 at 11:04 PM Bakul Shah  wrote:

> r := os.Open(filename)
> if isError(r) { return r.(error) }
> f := r.(*os.File) // or better: var f *os.File; f = r
>

This still does not seem meaningfully different to me, though.
* You are writing isError(r), instead of err != nil
* You are writing r.(error) instead of err
* You are writing f := r.(*os.File), but is that so different from just
using f?

Yes, the compiler will prevent you from using the result without a
type-assertion. That's a real benefit. But given that you are not really
meaningfully change the amount of boilerplate and the benefit of detecting
a possible bug can also be achieved using errcheck, I agree with Roger that
this doesn't seem that meaningful an improvement to justify adding a new
language feature.



>
> Error checking being a common pattern, isError() can be added as a builtin
> or trivially in errors pkg. Likely the enclosing function also returns an
> error
> so the return in the second line above can be just return r but with the
> current product type approach you’d have return nil, err.
>
> You are only looking at code after returning. Code within a function
> benefits
> more (gets simplified).
>
> func f(s string) (int|error) { // instead of (int,error)
>   ...
>   return err // instead of return 0,err
>   ...
>   return 1 // instead of return 1,nil
>   // and return n, err case disappears
>
> Having to return an extra thing that gets discarded right away is annoying.
> Early on this was a common mistake for me. We are used to it now but the
> current idiom came about because of a lack of sum types. People can use
> object{} as a return type today but that more or less defeats type checking
> which may be why returning an extra thing was perhaps seen as acceptable.
> So yes, I do think sum types benefit here. May be not enough for people to
> want a change but net benefit nonetheless.
>
> The bigger benefit is their use where people currently end up using
> object{}
> or product type. With sum types you get better documentation and checking.
> If you think of sum types as just restricted object{} types, they are
> simple to
> explain and implement. Simpler than what you guys were discussing on issue
> 19412 thread. I will add a comment there.
>
> On Feb 24, 2018, at 12:03 PM, roger peppe  wrote:
>
> >> I once counted there were about 8000 uses of ,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  wrote:
> >>> On Thu, 22 Feb 2018 12:55:01 + 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,
> >>

Re: [go-nuts] Appreciating Go

2018-02-24 Thread Bakul Shah
r := os.Open(filename)
if isError(r) { return r.(error) }
f := r.(*os.File) // or better: var f *os.File; f = r

Error checking being a common pattern, isError() can be added as a builtin
or trivially in errors pkg. Likely the enclosing function also returns an error
so the return in the second line above can be just return r but with the
current product type approach you’d have return nil, err.

You are only looking at code after returning. Code within a function benefits
more (gets simplified).

func f(s string) (int|error) { // instead of (int,error)
  ...
  return err // instead of return 0,err
  ...
  return 1 // instead of return 1,nil
  // and return n, err case disappears

Having to return an extra thing that gets discarded right away is annoying.
Early on this was a common mistake for me. We are used to it now but the
current idiom came about because of a lack of sum types. People can use
object{} as a return type today but that more or less defeats type checking
which may be why returning an extra thing was perhaps seen as acceptable.
So yes, I do think sum types benefit here. May be not enough for people to
want a change but net benefit nonetheless.

The bigger benefit is their use where people currently end up using object{}
or product type. With sum types you get better documentation and checking.
If you think of sum types as just restricted object{} types, they are simple to 
explain and implement. Simpler than what you guys were discussing on issue
19412 thread. I will add a comment there.

On Feb 24, 2018, at 12:03 PM, roger peppe  wrote:

>> I once counted there were about 8000 uses of ,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  wrote:
>>> On Thu, 22 Feb 2018 12:55:01 + Jesper Louis Andersen 
>>>  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

Re: [go-nuts] Appreciating Go

2018-02-24 Thread roger peppe
> I once counted there were about 8000 uses of ,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  wrote:
> On Thu, 22 Feb 2018 12:55:01 + Jesper Louis Andersen 
>  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 ,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 doabl

Re: [go-nuts] Appreciating Go

2018-02-23 Thread Bakul Shah
On Fri, 23 Feb 2018 17:39:16 -0800 Ian Lance Taylor  wrote:
Ian Lance Taylor writes:
> On Fri, Feb 23, 2018 at 5:23 PM, Bakul Shah  wrote:
> >
> > I once worked out some details of adding sum types to Go and I
> > think it is quite doable and easy to implement.
> 
> There is an extensive discussion of sum types in Go over at
> https://golang.org/issue/19412.

Thanks! Looks like Roger's ideas is similar. Not at all
surprising.  Will check it out further.

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-23 Thread Ian Lance Taylor
On Fri, Feb 23, 2018 at 5:23 PM, Bakul Shah  wrote:
>
> I once worked out some details of adding sum types to Go and I
> think it is quite doable and easy to implement.

There is an extensive discussion of sum types in Go over at
https://golang.org/issue/19412.

Ian

-- 
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.


Re: [go-nuts] Appreciating Go

2018-02-23 Thread Bakul Shah
On Thu, 22 Feb 2018 12:55:01 + Jesper Louis Andersen 
 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 ,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.


Re: [go-nuts] Appreciating Go

2018-02-22 Thread Jesper Louis Andersen
Usually, the type theoretic basis is what is called a sum-type. They are
corresponding to a logical OR or a '+' addition operation in algebra. A
"struct" is rightfully a variant of a product-type, or a logical AND or a
'*' multiplication operation in algebra[0]. Most (commonly used)
programming languages can "multiply" in the type system, but they can't
"add", and this creates a lot of serious problems since you have to
simulate sums through products.

If we write

type point struct {
   x int
   y int
}

you could argue that a value of type point contains "a value X" AND "a
value Y", which is why they are often called product types. Forming a point
point{x,y} mandates you supply both at the same time.

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

And then you can discriminate on this value via pattern matching

match res with
| Ok value -> ...
| Error err -> ...

This means that the inconsistent state cannot be represented. An ('a, 'b)
result is either "Ok ..." OR "Error ..." but it can't be both.

Go does have matching constructions which are special cases of the general
variant above. In particular, in OCaml we can have

match x with
| true -> ExprT
| false -> ExprF

(where ExprT/ExprF are arbitrary expressions) but this is same as (in fact,
syntactic sugar for):

if x then ExprT else ExprF

which is roughly equivalent to the following in Go[1]

if x {
ExprT
} else {
ExprF
}

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.

In practice, a programming language will contain a "pattern match compiler"
which compiles a pattern match into an if-maze, a jump table, binary search
and so on. This means they are efficient to execute in practice because you
can use positive and negative match information to skip match clauses when
needed. Two good references are Simon Peyton Jones compiler book[3] and
Peter Sestofts pattern match compiler[4]

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.

Rust calls them "enums" but they are more than just an enumeration in e.g.,
Java, because each variant also binds values. Scala calls them sealed
classes, and I guess it has to do with the language being heavely based on
Java and thus needs the concept to coexist with subtyping, but I may be
wrong in my guess.


[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.

[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

[4] http://dotat.at/tmp/match.pdf

On Thu, Feb 22, 2018 at 1:14 PM Josh Humphries 
wrote:

> On Thu, Feb 22, 2018 at 4:56 AM, Steven Hartland 
> wrote:
>
>> On 22/02/2018 09:46, andrewchambe...@gmail.com wrote:
>>
>> Just a list of things I like about Go, thanks everyone for the hard work:
>>
>> snip...
>>
>> Minor things that could be improved in order of importance:
>>
>> - Ways to express immutability ... as a concurrent language it can still
>> be easy to make mistakes and share a buffer or slice by accident.
>> - More advanced static analysis tools that can prove properties of your
>> code (perhaps linked with the above).
>>
>> Have you seen: https://github.com/alecthomas/gometalinter
>>
>> - Generics.
>> - Some sort of slightly more sophisticated pattern matching .
>>
>> Not sure what you mean here but have you seen:
>> https://golang.org/pkg/regexp/
>>
>
> I'm pretty sure Andrew was referring to pattern matching like in Scala and
> Rust. It's a very slick feature. Related: Rust's enum types are slick --
> they are like a combination of enums (such as in Java, and Scala) and
> Scala's sealed classes.
> https://docs.scala-lang.org/tour/

Re: [go-nuts] Appreciating Go

2018-02-22 Thread Josh Humphries
On Thu, Feb 22, 2018 at 4:56 AM, Steven Hartland 
wrote:

> On 22/02/2018 09:46, andrewchambe...@gmail.com wrote:
>
> Just a list of things I like about Go, thanks everyone for the hard work:
>
> snip...
>
> Minor things that could be improved in order of importance:
>
> - Ways to express immutability ... as a concurrent language it can still
> be easy to make mistakes and share a buffer or slice by accident.
> - More advanced static analysis tools that can prove properties of your
> code (perhaps linked with the above).
>
> Have you seen: https://github.com/alecthomas/gometalinter
>
> - Generics.
> - Some sort of slightly more sophisticated pattern matching .
>
> Not sure what you mean here but have you seen:
> https://golang.org/pkg/regexp/
>

I'm pretty sure Andrew was referring to pattern matching like in Scala and
Rust. It's a very slick feature. Related: Rust's enum types are slick --
they are like a combination of enums (such as in Java, and Scala) and
Scala's sealed classes.
https://docs.scala-lang.org/tour/pattern-matching.html
https://doc.rust-lang.org/1.6.0/book/match.html


>
> --
> 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.


Re: [go-nuts] Appreciating Go

2018-02-22 Thread Steven Hartland

On 22/02/2018 09:46, andrewchambe...@gmail.com wrote:

Just a list of things I like about Go, thanks everyone for the hard work:

snip...

Minor things that could be improved in order of importance:

- Ways to express immutability ... as a concurrent language it can 
still be easy to make mistakes and share a buffer or slice by accident.
- More advanced static analysis tools that can prove properties of 
your code (perhaps linked with the above).

Have you seen: https://github.com/alecthomas/gometalinter

- Generics.
- Some sort of slightly more sophisticated pattern matching .
Not sure what you mean here but have you seen: 
https://golang.org/pkg/regexp/


--
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.


[go-nuts] Appreciating Go

2018-02-22 Thread andrewchamberss
Just a list of things I like about Go, thanks everyone for the hard work:

Good things go has:

- Go has an extremely useful std library.
- Go has the best backwards compatibility I have seen (I'm pretty sure code 
from go version 1.0 still works today.).
- Go has the nicest code manipulation tools I have seen.
- The best race condition detector tool around.
- An incredibly useful in practice interface system. (I once tunneled http 
and ssh connections over a serial port because net.Listener and net.Conn 
are easy interfaces)
- The fastest compiler to use, and to build from source.
- Probably the best cross compilation story of any language, with 
uniformity across platforms, including ones you haven't heard of.
- One of the easiest to distribute binaries across platforms (this is why 
hashicorp, cockroachdb, ngrok etc choose go, it makes on boarding customers 
so much easier.).
- A very sophisticated garbage collector with low pause times.
- One of the best runtime performance to ease of use ratios around.
- One of the easier to learn languages around.
- A compiler that produces byte for byte identical binaries.
- incredibly useful libraries maintained by google: (e.g. Heres a complete 
ssh client and server anyone can  use: 
https://godoc.org/golang.org/x/crypto/ssh)
- Lots of money invested in keeping it working well from many companies: 
cloud flare, google, uber, hashicorp  and more.
- *FINALLY* A fresh and bold take on package management that isn't a cargo 
cult :) - https://research.swtch.com/vgo  (I especially like how well this 
tackles verifiable builds).

Minor things that could be improved in order of importance:

- Ways to express immutability ... as a concurrent language it can still be 
easy to make mistakes and share a buffer or slice by accident.
- More advanced static analysis tools that can prove properties of your 
code (perhaps linked with the above).
- Generics.
- Some sort of slightly more sophisticated pattern matching .



Let me know if I missed anything, thanks again.

-- 
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.