Earlier quoted context omitted.
This term is typically used to refer to things like data structures and numerical values all being passed as strings. I don't think a reasonable person would consider storing a username in a string to be "stringly typed".
It definitely is stringly typed. It's just that it's a very normalized example of it, that people don't think of as being an antipattern. If you want to implement what Yaron Minsky described as "make illegal states unrepresentable", then you use a username type, not a string. That rules out multiple entire classes of illegal states. If you do that, then when you compile your program, the typechecker can provide a muc…
How I write HTTP services in Go after 13 years
181–190 of 259 posts
Re: How I write HTTP services in Go after 13 years
#182Earlier quoted context omitted.
> Except for all those times you're the consumer of someone else's library and there's no way for them to indicate that creating a zero-valued struct is a bug. Nonsense. Go has a built-in facility for documentation to communicate these things to other developers. Idiomatic Go strongly encourages you to use it. Consumers of the libraries expect it. > Sometimes it's nice to work with a type system where designers of li…
You don't have to go as far as Coq. Rust manages "parse, don't validate" extremely well with serde. Go's zero-values are the problem, not any other lack of its type system.
No, you do. Anywhere the type system is incomplete means that the consumer can do something the library didn't intend. Rust does not have a complete type system. There was no relevance to mentioning it. But I know it is time for Rust's regularly scheduled ad break. And while you are at it, enjoy a cool, refreshing Coca-Cola.
> Go's zero-values are the problem
"Sometimes it's nice to work with a type system where designers of libraries can actually prevent you from writing bugs." has nothing to do with zero-values. It doesn't even really have anything to do with Go specifically. My, the quality of advertising has really declined around here. Used to be the Rust ads at least tried to look like they fit in.
Re: How I write HTTP services in Go after 13 years
#183Earlier quoted context omitted.
It definitely is stringly typed. It's just that it's a very normalized example of it, that people don't think of as being an antipattern. If you want to implement what Yaron Minsky described as "make illegal states unrepresentable", then you use a username type, not a string. That rules out multiple entire classes of illegal states. If you do that, then when you compile your program, the typechecker can provide a muc…
I don’t get what you’re about. The root comment clearly presents a structure of a separate type. The fact that it happens to contain a single string field is completely irrelevant (what type an actual username should be, a float?). “Stringly typed” is about stringifying non-string values to save typing work and is not applicable here in the slightest.
Re: How I write HTTP services in Go after 13 years
#184Earlier quoted context omitted.
I don't agree that this example is more "programmer friendly". Anything you want to do with the username other than null check and passing an argument is going to be based directly on the string representation. Insert into a database? String. Display in a UI? String. Compare? String comparison. Sort? String sort. Is it really more "programmer friendly" to create wrapper types for individual strings all over your code…
You inherit some code. Is that string a username or a phone number? Who knows. Someone accidentally swapped two parameter values. Now the phone number is a username and you’ve got a headache of trying to figure out what’s wrong. By having stronger types this won’t come up as a problem. You don’t have to rely on having the best programmers in the world that never make mistakes (tm) to be on your team and instead rely…
I would probably type to the level of Url, Email, Name but not PersonProfileTwitterLink.
Re: How I write HTTP services in Go after 13 years
#185Earlier quoted context omitted.
> Then the zero value is their problem, not yours. Except for all those times you're the consumer of someone else's library and there's no way for them to indicate that creating a zero-valued struct is a bug. Again, it's the philosophy of "Just do the right thing everywhere and you don’t have to worry!" Sometimes it's nice to work with a type system where designers of libraries can actually prevent you from writing b…
> Except for all those times you're the consumer of someone else's library and there's no way for them to indicate that creating a zero-valued struct is a bug. Nonsense. Go has a built-in facility for documentation to communicate these things to other developers. Idiomatic Go strongly encourages you to use it. Consumers of the libraries expect it. > Sometimes it's nice to work with a type system where designers of li…
Nobody is suggesting that Coq should be used, so stop bringing it up (strawman). And yes, Coq might have an even stricter and more expressive type system than Rust. But nobody is asking for a perfect type system (no true Scotsman). People are asking to be able to prevent users of your library to provide illegal values. Rust (and Haskell and Scala and Typescript and ….) lets you do this just fine whereas Golang doesn’t.
And personally I would much rather have the compiler or IDE tell me I’m doing something wrong than having to read the docs in detail to understand all the footguns.
My personal opinion is that - even though I’m very productive with Golang and I enjoy using it - Golang has a piss poor type system, even with the addition of Generics.
Re: How I write HTTP services in Go after 13 years
#186Earlier quoted context omitted.
You don't have to go as far as Coq. Rust manages "parse, don't validate" extremely well with serde. Go's zero-values are the problem, not any other lack of its type system.
> You don't have to go as far as Coq. No, you do. Anywhere the type system is incomplete means that the consumer can do something the library didn't intend. Rust does not have a complete type system. There was no relevance to mentioning it. But I know it is time for Rust's regularly scheduled ad break. And while you are at it, enjoy a cool, refreshing Coca-Cola. > Go's zero-values are the problem "Sometimes it's nice…
Re: How I write HTTP services in Go after 13 years
#187> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…
Re: How I write HTTP services in Go after 13 years
#188Earlier quoted context omitted.
Parse don't validate means that if you want a function that converts an IP address string to a struct IpAddress{ address: string } you don't validate that the input string is a valid IP address then return a struct with that string inside. Instead you parse that IP into raw integers, then join those back into an IP string. The idea is that your parsed representation and serializer are likely produce a much smaller an…
Thanks for that explanation! I hadn't appreciated that aspect of "parse, don't validate," before. But even with that understanding and from re-reading the post, that seems to be an extra safety measure rather than the essence of the idea. Going back to my original example of parsing a Username and verifying that it doesn't contain any illegal characters, how does a parser convert a string into a more direct represent…
IP address would be about the minimum amount of structure. Something else would be like processing API requests. You can take the incoming JSON and fully parse it as much as possible, rather than just validate it is as expected (for example drop unknown fields)
Re: How I write HTTP services in Go after 13 years
#189I agree with a lot of this, I'll add my own opinions: * I would pass a waitgroup with the app context to service structs. This way the interrupt can trigger the app shutdown via the context and the main goroutine can wait on the waitgroup before actually killing the app. * If writing a CLI program, then testing stdout, stdin, stderr, args, env, etc. is useful. But for an http server, this is less true. I would pass s…
Re: How I write HTTP services in Go after 13 years
#190Earlier quoted context omitted.
My favorite way to prevent this is to make the config truly immutable, but still configurable with something like this: package config type options struct { name string } type Option func(o *options) func Name(name string) Option { return func(o *options) { o.name = name } } type Config struct { opts *options } func New(opts ...Option) *Config { o := &options{} for _, option := range opts { option(o) } return &Config…
I used that pattern for a while but stopped using it. I first encountered it from this blog post: https://commandcenter.blogspot.com/2014/01/self-referential-... It's a lot of boilerplate to create something that's not actually immutable. It also makes it harder to figure out which options are available, since now you can't just look at the documentation of the type, you have to look at the whole module package to fi…
Sure you can. Option func is a constructor for option type, and constructors are auto-included above methods in the docs.
PLS completion works for them as well.