News for hackers. Stuff that matters.
Re:Go 1.18 by frenchie4111 on Tuesday March 15, 2022 @03:16PM (#30689904)
In celebration of generics release, I was playing around with supporting Optionals via generics. If anyone's interested I am happy to make this a real project

https://github.com/frenchie4111/go-generic-optional

Re:Go 1.18 by Mawr on Tuesday March 15, 2022 @04:00PM (#30690711)

  type Optional[T any] struct {
    value *T
  }
Don't use a pointer - it's bad for performance.

  func MakeOptional[T any](value *T) Optional[T] {
Use `New` instead - it's the idiomatic name for a constructor in Go. Drop the `Optional` part - the module name suffices - the caller will see: `opt.New`. Personally I just call the module `optional`, I think it's clearer: `optional.New`.

  func (o* Optional[T]) Unwrap() (T, error) { 
1. `Unwrap` reminds me of Rust's .Unwrap, which panics. Seems confusing.

2. There's no error here, the situation is equivalent to a missing key in a map - it's enough to return a bool.

Here's my implementation so far: https://gist.github.com/Mawr-BF2/0a60da26f66b82ee87b98b03336.... Only thing I'm not sure about is whether the JSON serialization methods are necessary.

Re:Go 1.18 by frenchie4111 on Tuesday March 15, 2022 @04:20PM (#30691025)
I love it. I will update the library to match some of your suggestions.

I agree with peer comment that we should likely defer to the original type for JSON serialization.

Re:Go 1.18 by kesslern on Tuesday March 15, 2022 @09:29PM (#30694200)
> Use `New` instead - it's the idiomatic name for a constructor in Go.

Where do you get this from? I've tried unsuccessfully to find such naming/design guidelines.

Re:Go 1.18 by dbaggerman on Tuesday March 15, 2022 @09:50PM (#30694343)
It's noted in the Effective Go guide: https://go.dev/doc/effective_go#package-names
Re:Go 1.18 by morelisp on Tuesday March 15, 2022 @04:28PM (#30691159)
Whether a pointer is bad for performance in this case seems hard to tell a priori. There are also performance advantages if Optional packs nicely.
Re:Go 1.18 by Mawr on Tuesday March 15, 2022 @05:04PM (#30691698)
It is just an assumption on my part, I figure that the cost of pointer chasing is generally going to outweigh any disadvantages. It can also help enable optimizations, for example slices and maps that do not contain pointers do not get scanned by the GC ([1]).

[1]: https://github.com/golang/go/commit/85e7bee19f9f26dfca414b1e...

Re:Go 1.18 by stingraycharles on Tuesday March 15, 2022 @06:13PM (#30692584)
I fully agree with your approach. The important thing is that the user now has the choice to use a pointer or not: they can always use a pointer to the optional if they want to use pointers.

Pointers to pointers are generally something you try to avoid if possible.

Re:Go 1.18 by morelisp on Tuesday March 15, 2022 @07:12PM (#30693182)
> the user now has the choice to use a pointer or not

But any benefits of the packing are gone whether I make a pointer or not.

And either way, no nested pointers are involved. We’re not taking pointers to options in either case.

Re:Go 1.18 by frenchie4111 on Tuesday March 15, 2022 @04:40PM (#30691329)
Agreed on performance being in the air. Tbh, I like the non-pointer option because using a pointer was causing the implementation to feel a bit weird. This cleans up a bit of the handling that was annoying (for example in the old implementation Make(&"something") didn't work because you can't reference a constant without first making a variable.
Re:Go 1.18 by wtfishackernews on Tuesday March 15, 2022 @04:11PM (#30690870)
For json marshalling, I would defer to the underlying type's marshalling if it's present, and return `null` otherwise.
Re:Go 1.18 by shhsshs on Tuesday March 15, 2022 @04:46PM (#30691440)
I think this is appropriate in some cases but not others. For example how does the JSON value distinguish between `Some(null)` and `None`?
Re:Go 1.18 by dialogbox on Tuesday March 15, 2022 @06:37PM (#30692861)
IMO using Optional type means the inner value must be not null. And if it's Some(null), it should mean exactly same as None.
Re:Go 1.18 by uryga on Tuesday March 15, 2022 @07:22PM (#30693267)
distinguishing `Some(null)` and `None` is often considered a feature of Optional ;)

to use a tired example: when getting a value out of a map via some `myMap.get(key)`, you may want to distinguish "not present" = `None` and "present, with value null" = `Some(null)`

the right solution is to just not have nulls in the first place, then there's no problem ;)

Re:Go 1.18 by alophawen on Tuesday March 15, 2022 @10:53PM (#30694795)
(Assuming we are discussing the Option type from rust)

Some(null) is not a valid result.

The whole point of the Option type is to let you know:

a) we got a result: Some(value)

b) there is no result: None

Re:Go 1.18 by andrewjf on Wednesday March 16, 2022 @10:32AM (#30699303)
It's trivial to store a null pointer in an Option::Some().

  struct Foo;
  
  fn main() {
      let option_with_null: Option<*const Foo> = Some(std::ptr::null());
  
      dbg!(option_with_null);
      dbg!(option_with_null.is_none());
  }
Output:

  [src/main.rs:6] option_with_null = Some(
      0x0000000000000000,
  )
  [src/main.rs:7] option_with_null.is_none() = false



https://play.rust-lang.org/?version=stable&mode=debug&editio...
Re:Go 1.18 by alophawen on Wednesday March 16, 2022 @03:58PM (#30703290)
As the creator of the function, you should try to adhere to the conventions and not try to break them.
Re:Go 1.18 by andrewjf on Wednesday March 16, 2022 @06:57PM (#30705226)
I don't disagree, but:

> Some(null) is not a valid result.

It is a valid result. Null pointer and Option::None are still different things, is all.

Re:Go 1.18 by the-smug-one on Tuesday March 15, 2022 @07:44PM (#30693444)
> Don't use a pointer - it's bad for performance.

That means you must have Optional[*sync.Mutex]. Then what's the point?

Re:Go 1.18 by baby on Wednesday March 16, 2022 @05:06AM (#30696708)
Wondering how a result type would be implemented
Re:Go 1.18 by assbuttbuttass on Tuesday March 15, 2022 @05:16PM (#30691828)
This looks kind of cool, but I think there's no version of this as a library that could be considered idiomatic(TM), after all "a little copying is better than a little dependency"

https://go-proverbs.github.io/

Re:Go 1.18 by svnpenn on Wednesday March 16, 2022 @12:39AM (#30695379)
Why can't you just do something like this:

    func hello() (string, bool)
Re:Go 1.18 by Mawr on Friday March 18, 2022 @11:36PM (#30730738)
You can, and in fact, that's how idiomatic Go's handled this up until now. But it only works in that specific case, and even then there's a small issue with readability - if you're not already familiar with this pattern, it's not immediately obvious that the string is strongly coupled with the bool. An Optional is very explicit about that.

The problem becomes clearer once you venture out of this exact case. How would you embed this pattern in a struct?

Like so?

  type A struct {
      value string
      valueOK bool
  }
Or maybe with a pointer?

  type B struct {
      value *string
  }
This option is the most common one in Go code today.

You can perhaps see the issues already - these are awkward, neither properly communicates that what we want is optionality.

But the real issue is that now that these are in a struct, nothing prevents us from accessing the value without checking if it's valid first:

  a := A{value: "", valueOk: false}
  // oops
  fmt.Println(a.value)

  a := B{value: nil}
  // oops
  fmt.Println(a.value)
This wasn't an issue in your example - if we attempt to only access the value, and omit assigning the bool, the code will not compile:

  func hello() (string, bool) {
      return "hi", false
  }

  func main() {
      value := hello()
      // ^^^ compiler error: assignment mismatch: 1 variable but hello returns 2 values ([1])
      fmt.Println(value)
  }
An Optional type fixes this by not allowing you to access the value directly, but to instead have to go through a function like the one above.

[1]: https://play.golang.com/p/cJcTD0WWSPO

Re:Go 1.18 by pharmakom on Tuesday March 15, 2022 @04:51PM (#30691521)
Optionals without do notation will be a bad time.
Re:Go 1.18 by LAC-Tech on Tuesday March 15, 2022 @06:41PM (#30692898)
What's do notation?

I've used optionals in many languages, and this is the first I've heard of it. What else do you really need except map and... flatMap (aka `then` aka `and_then` aka `>>=` aka `bind`).

Re:Go 1.18 by uryga on Tuesday March 15, 2022 @07:32PM (#30693349)
https://en.m.wikibooks.org/wiki/Haskell/do_notation

rough analogy: `await` replaces `.then()`, do-notation replaces `.flatMap()`

Re:Go 1.18 by int_19h on Tuesday March 15, 2022 @10:08PM (#30694451)
C# has had Nullable<T> for many years before it got stuff like ?. and ?? that mostly covers this, and it was, well, tolerable.
Re:Go 1.18 by BoorishBears on Tuesday March 15, 2022 @11:58PM (#30695153)
Ergonomics sucked and a lot of people didn't use them (or even know they existed!) because ergonomics sucked
Re:Go 1.18 by int_19h on Wednesday March 16, 2022 @06:21AM (#30697090)
From my work experience at the time, it was used pretty heavily in new codebases.
Re:Go 1.18 by BoorishBears on Wednesday March 16, 2022 @12:00PM (#30700466)
I mean the fact that they've been around since 2.0 but you saw it used heavily in new codebases says a lot doesn't it?
Re:Go 1.18 by int_19h on Wednesday March 16, 2022 @07:55PM (#30705730)
You misunderstood - I saw them in codebases that were new back when .NET 2.0 was new.

To be more precise, it was when .NET 3.5 was new (2008). That brought a lot of visibility to Nullable<T> because it was featured prominently in LINQ. But ?. didn't come until C# 6 (2014). I was wrong about ??, though - that one was added along with Nullable itself.

Re:Go 1.18 by daptaq on Tuesday March 15, 2022 @04:32PM (#30691208)
My main fear with the introduction of generics was the lack of stdlib support. I know they want to play it safe and are planning to change this in future versions, but the last thing I want is that I have to download some github.com/foobar/... library for every common sense generic type I might want to use.
Re:Go 1.18 by heavyset_go on Tuesday March 15, 2022 @06:17PM (#30692620)
Agree with this sentiment. It was a very good idea to bring the `typing` module into the Python standard library versus just relying on Mypy.
Re:Go 1.18 by mountainriver on Tuesday March 15, 2022 @04:53PM (#30691540)
Awesome work! I would love to see something like this make it into the language