1) proper dependencies management system (the new module system might address this) and
2) gener... nah, just kidding -- actually null protection. I don't want to see another segfault or null pointer failure ever again.
If it had these two features, I'd probably stop toying around with Rust and Crystal and just use Go. Unfortunately, 2) is probably impossible without seriously breaking old code, and they're not gonna break old code.
Totally agree on 2. "Learn a language a year" they said. "Learning new languages expands your thinking" they said. What they didn't say was that once you use ADTs to model data, Maybe/Option types to avoid null, exhaustive pattern matching, etc, you want those features in all the languages you use.
I don't ask for much. I just want a GC'd Rust (one of the few modern languages that has option types in the std lib) or an F# that isn't tied to the .NET standard lib. Please?
In regards to 2: I find it difficult sometimes to work with a language that doesn't have Elixir/Erlang's pattern matching, and sometimes I wish I hadn't learned about it...
(the pipe operator is another favorite I miss often)
I actually stopped learning new languages with these features because I started to get so frustrated they weren't available. Or I implemented then am everyone got weirded out by their 'strangeness'
Nil exception handling is horrible in go. The thing wasn’t designed to handle pointers and blows up left and right once someone tries to use them (or untyped objects).
When have you seen segfaults in Go? I think 100% of the time, it is either a bug in the Go runtime, or you're using cgo (which is not really Go anymore).
A language as simple as Go without nilable types would be great, though.
C programs tend to call nil-pointer panics "segfaults" even though go runtime doesn't print the word "segfault" anywhere. I'm guilty of the same thing.
Agreed with 2. I honestly don't understand why the compiler doesn't do analysis to catch such cases. As someone who doesn't work on these things, perhaps it's too intensive? I've made silly nil pointer mistakes before and wondered why the compiler didn't say 'hey dummy, look what you did here'.
Re. "null protection": It is kind of hard to fit non-nullable pointers into Go. The fact that non-nullable pointers do not have a natural initial value and always require an initial assignment is especially problematic in Go's struct semantics, because first of all, struct creation is supposed to be light-weight. If a struct contains pointers, the cheapest way to initialize it would be to assign them nil.
But the more interestingly problem is how Go's struct "constructor" works. It is very low-level, you just assign some fields in a struct like &SomeStruct{X: 1, Y: "y"}; you can also assign all fields, in which case you can omit the keys, like &SomeStruct{1, "y"}. let's call those the key-value variant and positional variant of "free-form constructor".
You can provide a "function constructor", which is simply a function that returns SomeStruct or * SomeStruct, but it is not required, nor can you forbid the free-form constructor.
This is in stark contrast with, say, Java, where the function constructor is both required and the only allowed form. That makes it easy to make sure that non-nullable pointer fields are always initialized, because the compiler only needs to check the constructors.
In Go it is much harder. You can make the free-form constructor check that non-nullable pointer fields get initial values, but then Go has this promise that the author of a struct can add new fields without breaking users of the free-form constructor, as long as they are using the key-value variant instead of the positional variant. So if a struct was originally:
type SomeStruct {
X int
Y string
}
A user can make an instance with &SomeStruct{X: 1, Y: "y"}. If the author of the struct decides to add a new field, the code should still work. That should be the case even if the new field is a non-nullable pointer field. This now defeats the purpose of non-nullable pointer fields.
> but then Go has this promise that the author of a struct can add new fields without breaking users of the free-form constructor, as long as they are using the key-value variant instead of the positional varian
This is the bit that would need to change. And actually, doing so would provide the same benefits that non-nullable types do in other contexts.
Say a Go library user is using a struct in 5 places, and the library author adds a new field. The user updates the free-form constructor to properly initialise the new field in 4 of those 5 places, but overlooks the 5th. As it stands, that will fail silently if the program is relying on using a non-null value somewhere else in the code. If upgrading the library caused a compile time error then that bug would have been caught.
Rust also has "free-form constructors" like Go, and this is the approach it takes: you must provide a value for all fields.
> first of all, struct creation is supposed to be light-weight.
Non-nullable pointers don't make struct creation any more expensive.
> You can provide a "function constructor", which is simply a function that returns SomeStruct or * SomeStruct, but it is not required, nor can you forbid the free-form constructor.
You can have an exported function returning a non-exported type. This restricts the "freeform" constructor to the package's internal's. It severely limits the caller's ability to use it (unless you also provide an interface to work with), but it's there.
The new official way of package management is vGo. Dep was an experiment which was suucceded by vGo, which in 1.11 is officialy (beta) included in the Go toolkit and will be the main way in Go 1.12.
There's a great blog post series about it (though it's dense, plan to spend a few hours to read it all: https://research.swtch.com/vgo)
A change to gofmt like that is going to require a large formatting commit to conform. Presumably/ideally there are CIs that fail on invalid format, so it's not like you can wait until you touch the file again. Not a big deal, but still worth noting.
"""Note that these kinds of minor updates to gofmt are expected from time to time. In general, we recommend against building systems that check that source code matches the output of a specific version of gofmt. For example, a continuous integration test that fails if any code already checked into a repository is not “properly formatted” is inherently fragile and not recommended."""
> For example, a continuous integration test that fails if any code already checked into a repository is not “properly formatted” is inherently fragile and not recommended.
As a frequent repo/commit spelunker, I'm gonna have to disagree here. It is better to have this changed all in one commit instead of tacking on that formatting change along with an unrelated change elsewhere in the file and doing that all over the place at separate times. What's inherently fragile (formatting wise) is making a change to a file that does not meet the current formatting requirements and then having it format on save/commit, messing up blames, code review diffs, etc.
Ideally, CI won't fail on invalid format, but just politely apply the correct format. There's nothing more frustrating than being told to do a job a machine can trivially to better (like executing "gofmt").
That is correct. Now you can clone and build Go repos anywhere.
Note that support is still experimental, so if you want stability, it is advised to remain inside GOPATH for another release. This is a good post - https://systemdump.io/posts/2018-07-22-go-modules
However, do please feel free to try it out and file bugs.
It actually could cause bigger problems than that. Most Go projects I've seen have CI runs that check whether 'gofmt' complains -- and fail builds if they do.
Ultimately though I don't really care all that much. Everyone will fix it in a few commands, and everything will be green again.
In this specific case it doesn't do that: any time you add or remove a field from a structure, if it's one of the "extremes" gofmt might re-pad the entire thing, churning the entire structure.
1) proper dependencies management system (the new module system might address this) and
2) gener... nah, just kidding -- actually null protection. I don't want to see another segfault or null pointer failure ever again.
If it had these two features, I'd probably stop toying around with Rust and Crystal and just use Go. Unfortunately, 2) is probably impossible without seriously breaking old code, and they're not gonna break old code.
I don't ask for much. I just want a GC'd Rust (one of the few modern languages that has option types in the std lib) or an F# that isn't tied to the .NET standard lib. Please?
I think they’re doing a compiler rewrite that steals the good ideas from Rust (like good error messages).
F# is basically OCaml on .Net, so… OCaml?
(the pipe operator is another favorite I miss often)
Nil exception handling is horrible in go. The thing wasn’t designed to handle pointers and blows up left and right once someone tries to use them (or untyped objects).
Dependency management is a total mess.
A language as simple as Go without nilable types would be great, though.
But the more interestingly problem is how Go's struct "constructor" works. It is very low-level, you just assign some fields in a struct like &SomeStruct{X: 1, Y: "y"}; you can also assign all fields, in which case you can omit the keys, like &SomeStruct{1, "y"}. let's call those the key-value variant and positional variant of "free-form constructor".
You can provide a "function constructor", which is simply a function that returns SomeStruct or * SomeStruct, but it is not required, nor can you forbid the free-form constructor.
This is in stark contrast with, say, Java, where the function constructor is both required and the only allowed form. That makes it easy to make sure that non-nullable pointer fields are always initialized, because the compiler only needs to check the constructors.
In Go it is much harder. You can make the free-form constructor check that non-nullable pointer fields get initial values, but then Go has this promise that the author of a struct can add new fields without breaking users of the free-form constructor, as long as they are using the key-value variant instead of the positional variant. So if a struct was originally:
type SomeStruct { X int Y string }
A user can make an instance with &SomeStruct{X: 1, Y: "y"}. If the author of the struct decides to add a new field, the code should still work. That should be the case even if the new field is a non-nullable pointer field. This now defeats the purpose of non-nullable pointer fields.
This is the bit that would need to change. And actually, doing so would provide the same benefits that non-nullable types do in other contexts.
Say a Go library user is using a struct in 5 places, and the library author adds a new field. The user updates the free-form constructor to properly initialise the new field in 4 of those 5 places, but overlooks the 5th. As it stands, that will fail silently if the program is relying on using a non-null value somewhere else in the code. If upgrading the library caused a compile time error then that bug would have been caught.
Rust also has "free-form constructors" like Go, and this is the approach it takes: you must provide a value for all fields.
Non-nullable pointers don't make struct creation any more expensive.
> You can provide a "function constructor", which is simply a function that returns SomeStruct or * SomeStruct, but it is not required, nor can you forbid the free-form constructor.
You can have an exported function returning a non-exported type. This restricts the "freeform" constructor to the package's internal's. It severely limits the caller's ability to use it (unless you also provide an interface to work with), but it's there.
There's a great blog post series about it (though it's dense, plan to spend a few hours to read it all: https://research.swtch.com/vgo)
Dead Comment
What? Are they removing “godoc <pkg>”? I used that a lot as a man page. It’s especially useful when you don’t have internet access
Edit: it’ll still be available in `go doc`, just that `godoc` will only be a web server. https://tip.golang.org/doc/go1.11#godoc
https://raw.githubusercontent.com/mvdan/talks/master/2018/go...
"""Note that these kinds of minor updates to gofmt are expected from time to time. In general, we recommend against building systems that check that source code matches the output of a specific version of gofmt. For example, a continuous integration test that fails if any code already checked into a repository is not “properly formatted” is inherently fragile and not recommended."""
As a frequent repo/commit spelunker, I'm gonna have to disagree here. It is better to have this changed all in one commit instead of tacking on that formatting change along with an unrelated change elsewhere in the file and doing that all over the place at separate times. What's inherently fragile (formatting wise) is making a change to a file that does not meet the current formatting requirements and then having it format on save/commit, messing up blames, code review diffs, etc.
Server-side you have the check.
Client-side you have a hook that runs gofmt when you commit, and in principle you’ll never hit the server-side check.
Just in case something goes wrong -- and something somewhere always goes wrong -- you don’t want the server to silently rewrite stuff on your behalf.
Note that support is still experimental, so if you want stability, it is advised to remain inside GOPATH for another release. This is a good post - https://systemdump.io/posts/2018-07-22-go-modules
However, do please feel free to try it out and file bugs.
- WebAssembly and Modules have already been covered.
https://github.com/golang/go/wiki/Modules
Ultimately though I don't really care all that much. Everyone will fix it in a few commands, and everything will be green again.