Earlier quoted context omitted.
Ah, I think the bit where generics is useful is in making sure the value types are consistent (i.e., that you're not building a query that subtracts an int from a string or compares a date to a bool). This still doesn't guarantee that the types will match with the database columns, but it is a step up from the non-generic alternative.
I keep meaning to pick up Rust, still looking for some entry point that's interesting enough to get me off my butt. How (well) does diesel deal with migrations? I've seen other ORMs fall down the stairs trying to deal with schema modification over time.
Toward Go 2
601–610 of 670 posts
Re: Toward Go 2
#602Earlier quoted context omitted.
Then they should ask for that instead. It's not unreasonable to ask "how do we implement this in the best way?", but I'll note a) that's not what was asked, and b) I have a hard time believing that code at Google is so incredibly "special" that they need a special kind of generics. Also, if Google is such a unique snowflake why not ask the Google people directly rather than the "Go community"?
> "how do we implement this in the best way?" They asked for use cases from a wide range of people to ensure they implement it in the best way. Subtly different, but essentially the same request. > I have a hard time believing that code at Google is so incredibly "special" that they need a special kind of generics. I didn't say they need special generics. I said the approach that works best at Google may not be the b…
Phrasing is important, and obviously (from the reactions of me and others in the thread) the phrasing was way off and perceived as condescending and lazy.
> I didn't say they need special generics. I said the approach that works best at Google may not be the best approach for the population at large. If Google is best served by C++-style generics, while the community as a whole would be better served by Haskell-style generics, why just jump in and do it the C++ way before seeing how others might want to use it?
OK, so you said they don't need a special generics, but then say that they do. I must not be understanding what you're trying to say. (If this is about choosing trade-offs, then see the other poster who talked about trade-offs. Executive summary: Not doing generics is also a trade-off.)
Also: ASK GOOGLE.
> Because they are trying to avoid the mistake of using one datapoint like Go has struggled with in the past? They know what works in Google, but that doesn't necessarily work for everyone else. See: Package dependencies, among many.
You can't have it both ways. Either Google is important enough to it in a way that works for them, or the community is more important and they get to choose.
Anyway, I'm done with this conversation. I think we may be seeing this from viewpoints that are so different that it's pointless to continue.
I'm not sure how to argue constructively with someone who says "I'm not saying X, but..." and then immediately states a rephrasing of "X". I'm sure that's not what you think you are doing, but that's the way I'm seeing it, FWIW.
Re: Toward Go 2
#603Earlier quoted context omitted.
Not only that, but you can just ignore errors during prototyping and with a little editor magic you can go back easily generate at least 85% of the if err != nil {... etc. statements. As much as people complain about it, explicitly checking errors like this (and checking them all) is almost essential for production quality enterprise code and any code running on mission critical systems (and to most project managers,…
I think the "embrace failure" supervisor model in BEAM is a superior design for mission-critical systems (such as cell networks, where it originated) while resulting in literally a ton less boilerplate. You just code the "happy path" and done. Any errors are logged and the process instantly restarted by the supervisor, you can follow up on them if they present a problem. If you were to code just this "happy path" in…
Re: Toward Go 2
#604Earlier quoted context omitted.
Except they seem to focus only on Java, .NET and C++, forgetting that generics were initially implemented in CLU back in 1975, and there were several programming languages since those days that had some form of generics being designed into them.
Any thoughts on Eiffel's implementation of generics? https://en.wikipedia.org/wiki/Eiffel_(programming_language)#...
Re: Toward Go 2
#605Earlier quoted context omitted.
> Dart's choice of an unsound type system doesn't actually matter for those gradual typing problems we were talking about. I think you are getting too caught up in that point. I was trying to show that "gradual typing" should be possible in any reasonable static type system, without resorting to unsoundness. I do concede that there is probably a definition of the term "gradual typing" out there that I am not strictly…
> I do concede that there is probably a definition of the term "gradual typing" out there that I am not strictly adhering to. The basic goal of gradual typing is that you can have your program be fully untyped or fully typed or somewhere in between and it will behave in a sensibly in all cases. Adding types to a program does not change the result of the program, except that sometimes adding types may cause new type e…
> With this restriction, you cannot assign an accurate static type to a function with a dynamically typed implementation, which means that you can't use dynamically typed libraries from inside statically typed code.
It depends what you mean by an accurate type. A accurate type for adapting your example would be to expose Variant -> Variant as Int -> Maybe Int, thus capturing the partiality. I concede that Int -> Maybe Int cannot be used in a function that expects Int -> Int, but that is how it should be! An untyped language cannot provide me with a function of Int -> Int.
Re: Toward Go 2
#606I should send this to rsc, but it's fairly easy to find examples where the lack of generics caused an opportunity cost. (1) I started porting our high-performance, concurrent cuckoo hashing code to Go about 4 years ago. I quit. You can probably guess why from the comments at the top of the file about boxing things with interface{}. It just got slow and gross, to the point where libcuckoo-go was slower and more bloate…
For (1), for curiosity sake, I tried benchmarking the cuckoo.go file you posted. I'm curious if these numbers are in line with what you found. The first test I did was a Rand test, Putting 10,000 random string values under random string keys, then Getting the same 10,000 keys, then Getting 5000 more random keys. The first line below uses default code you posted, which uses
type keytype string
type valuetype string
The second line specializes the code to just using the string type directly for keys and values. The third line uses interface{} instead for values, which is the code style HN doesn't like. BenchmarkRandInsert-8 100 13474408 ns/op
BenchmarkStringStringRandInsert-8 100 13585071 ns/op
BenchmarkStringVoidStringRandInsert-8 100 14126666 ns/op
That third line shows the cost of casting to/from interface{}. The difference in the code was about as you might expect, with the "void" example needing a cast on each put and a cast on each get.If I use uint32 for value instead, I get:
BenchmarkStringIntRandInsert-8 200 9431584 ns/op
BenchmarkStringVoidIntRandInsert-8 100 10485785 ns/op
The 9.4ms result is using a version of your code hand-specialized for string key and uint32 values. The 10.4ms result uses interface{} for values.I ran a sequential-insert test as well, with keys and values generated sequentially instead of randomly. The results are much the same, though the cost of casting to/from interface{} seems to get mostly lost in the noise.
BenchmarkSequentialInsert-8 100 12185272 ns/op
BenchmarkStringStringSequentialInsert-8 100 12233946 ns/op
BenchmarkStringVoidStringSequentialInsert-8 100 12543980 ns/op
BenchmarkStringIntSequentialInsert-8 200 8823747 ns/op
BenchmarkStringVoidIntSequentialInsert-8 200 8709242 ns/op
I also tried some tests using uint32 as the key type. This int key specialized version is 3x faster than any of the string key versions, but it's not really a fair comparison... a small part of the code is specific to string keys (getinthash), so it's not as obvious what the generic equivalent of that function would be. The keys need to be Hashable or some such, not just interface{}. I'm also allocating and formatting random strings in one case, vs just picking random numbers in the other case.I didn't find the interface{} casting in any of the above code too horribly "gross", just a bit ugly, but that's entirely subjective. Yes, all of the cuckoo versions seemed about 30% slower than the corresponding builtin map type, but my benchmark numbers don't show if that is the price of boxing, of supporting concurrency, or maybe function call overhead, or something else. I'm guessing you did more detailed benchmarks that point to the source of the slowdown.
One last comment: keytype and valuetype really need to be exported, don't they? I wasn't able to use the library without changing them to exported symbols.
Re: Toward Go 2
#607Earlier quoted context omitted.
Generics in Go: https://twitter.com/snoyberg/status/882255351382462464
It really reminds me of early C macros where people use the ## operator to synthesize monomorphized versions.
Re: Toward Go 2
#608Earlier quoted context omitted.
> I had thought enums can only be used as named types. Good to know they can hold data as well. That depends on the language, and enums being sum types also depends on the language. * Rust and Swift enums are sum types (they can hold data and every variant can hold different stuff), there is also a ton of (mostly functional) languages with sum types not called enum: Haskell, F#, OCaml, … there are also languages whic…
Minor nitpick: case classes in Scala are product types, not sum types. I think you meant "sealed traits".
Re: Toward Go 2
#609Earlier quoted context omitted.
> For loops do not get the job done easily enough. There was a nice paper at this years POPL which (in my opinion) allows you to substantiate this claim. The paper is "Stream Fusion to Completeness", by Oleg Kiselyov, Aggelos Biboudis, Nick Palladinos, and Yannis Smaragdakis. The actual question in the paper is how to compile away stream operations to imperative programs using for/while loops and temporary variables.…
This all depends on what "the job" being done well enough is. You can't use a research paper to refute the experience of the many programmers who successfully use for loops to get their work done. That's a statement about usability, not expressiveness. If you want to show something else is easier to use, you'd have to do a user study, and even that's not going to be universally applicable since it depends on the prev…
They all show that the natural expression is through declarative programming and that for loop are never what comes naturally.
Re: Toward Go 2
#610Earlier quoted context omitted.
Not quite. The article mentions that Go 1 code needs to be able to coexist with Go 2 in the same codebase. So, at runtime, Go 1 code needs to be able to work with Go 2 types. That will impose some restrictions, I imagine.
>The article mentions that Go 1 code needs to be able to coexist with Go 2 in the same codebase. Interesting. Are there any other languages where that is allowed? I'm assuming that by "codebase" you mean all the code that gets compiled into one program or library (for compiled languages), or is part of one program or library (for interpreted languages). And I don't mean the case where only a common subset of Lang X v…
Perl 5/6
The various language feature pragmas in Haskell.