So do we like Generics or not?
source link: https://changelog.com/gotime/286
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Transcript
Changelog
Click here to listen along while you enjoy the transcript. š§
Hello there, welcome to Go Time. Iām Mat Ryer, and I have a cold. Sorry about thatā¦ Donāt worry, weāve got good editors, you probably wonāt notice anything. But I just wanted to let you know Iām not a hero, Iām just doing my bit for the Go community. So please feel free to celebrate that on Twitter.
Today, weāre talking about generics. Weāre asking āSo do we like generics or not?ā Some people feared that theyād be the end of the languageā¦ You know, that people would abuse it, and use them in all the wrong places. Others were a bit more hopeful. They had clear use cases, and were kind of thrilled that weāre getting this feature. But it was also often touted as the reason a lot of people didnāt adopt Go. So we have it now; we have generics, our flavor of generics. What do we think of it? Joining me to discuss this - itās my co-host, Kris Brandow. Hello, Kris.
Hello, Mat. How are you doing?
Iām not too bad. Iāve got a bit of a cold, but getting through it. Iām just [unintelligible 00:01:43.08] really just been brilliant. How about you?
Doing great. Itās a beautiful morning.
Good. Yes. And I appreciate this is quite early for you. Weāre doing this at a different timeā¦ So thanks for getting up so early.
Weāre also joined by Roger Peppe. Roger has been a Go enthusiast since the day it was released, and has been contributing loads of things to the standard library and the ecosystem. Currently working on implementing modules in the CUE language, cuelang.org. Welcome back, Roger.
Hi! Howās it going?
Good. Not bad. Pleasure to have you back, of course. I like your hoodie. For those that donāt know, heās wearing a CUE hoodie.
Itās my favorite hoodie.
Yeah. Weāre also joined by Bryan Boreham. Bryanās a distinguished engineer at Grafana Labs, working on highly scalable storage for metrics, logs and traces. Bryanās used Go since 2014, so again, a long time there, and contributes to many open source projects, including - you may have heard of Prometheus, perhaps youāve used gRPC, and I know a lot of you have used Go itself. Welcome, Bryan. Welcome back.
Hi. Thanks for having me.
Pleasure. Cool. So Iām very excited about this episode, because I was one of those people that was ā Iād used generics in previous languages, and I kind of was excited that we were getting it. How do we feel like ā maybe we could just give someone a quick overview of what generics are and when they came to go, just so everyoneās caught up. Any volunteers?
[laughs] Okay. Yeah, I mean, generics - they basically mean you can pass types to functions and methods, and you can have types that are themselves associated with types. Itās all at compile time. In a sense, you donāt need generics, but it means that you can have these things which ā where before you might pass a dynamic interface value, and maybe do a type coercionā¦ The classic case, of course, is with containers. So Iāve made this nice, advanced data structure that holds all my values, and I put a value in, and I know that Iām only going to put integers in there, and I get this thing out, and - oh, itās not an integer anymore. Itās the empty interface. So I have to assert that itās an interface, that itās an int, but maybe I didnāt actually put it into there, and so my program panics at runtime.
Also, there are a bunch of performance improvements associated with that, because in that particular example, putting an integer in an interface - if itās greater than 256 or something like that, then itās actually going to have an allocation to put that in an interface. So youāre actually paying the price of storing that data, where in fact you just actually only need one little integer-sized slot for it, and that can really [unintelligible 00:04:26.02] Particularly when you have larger data structures which incorporate types. The safety and the performance aspects, both can add up a lot in larger systems, I think.
I think I might want to note that we had some generic types before, since the beginning pretty much; like a map, for instance. Whenever you used a map, you had to put in square brackets what the key type was, and then right after that what the value type was. So map string of string, map int o string, or whateverā¦ And so what changed - was it Go 1.18? What changed is the kind of availability of the programmer to define their own things, their own types and functionsā¦. Which still had those little square brackets bit with a type in the middle. So the power was kind of reserved to the Go compiler beforehand, and now we have the power.
Yeah. And have we been wielding that power responsibly?
Well, I was a C++ programmer for a long time, 20 yearsā¦ And actually, from the time before C++ had generics.
And I think a lot of people feared that Go would suffer the way C++ did, because people started writing programs that frankly no one could understand, using templates, which is the same thing, basically, in C++. I feel Go has largely escaped that. I personally have not really come across people overusing generics.
[00:06:02.16] I think itās kind of too early to say, honestly. Weāre just past the point where people are generally using it, where people [unintelligible 00:06:08.20] And I think ā give it a couple of years, two or three years and weāll see, I think, whether things are moving in a dubious direction or not.
Yeah. What do you think about the choice of square brackets? Somebody that was quite new to the language was kind of surprised that it was just using square brackets and not something different, because it was such a different concept. Bryan, you make a good point about maps and slices being kind of the mapsā¦
Well, yeah, slices, the type, was outside the square brackets. Itās not a great pattern.
And maps too, right?
Well, yeah, maps - you have one type inside the square brackets and one outside. I donāt know if we could read too much into that. C++ itās angle brackets; itās less than/greater than, so I guess they wanted to distinguish themselves from that.
Well, angle brackets are problematic, right? Deeply problematic, because youāre syntactically ambiguous, because you canāt tellā¦ If youāve got a<b, then you canāt tell āIs that the start of a type parameter, or is it not?ā And I think thereās lots of good reasons not to use angle brackets for that reason.
I think thatās the same reason we didnāt use parentheses as well, because there was some syntactic ambiguityā¦
Actually, the first generics proposal in Go - well, the first serious generics proposal in Go did use parentheses. So you really can use parentheses, but I think in that case they were considered not sufficiently distinguished. The square brackets - itās somewhat distinguished, but notā¦ Yeah, thereās still some ambiguity there.
Right. So I guess that would be semantic ambiguity on the human side of like āWhat is this thing saying?ā if you use regular parentheses instead of brackets.
Yeah, I think that would look quite weird. Iām just trying to imagine what it would look like with parenthesesā¦
Yeah, indeed, there were just loads of parentheses. Are we Lispā¦? [laughter]
Yeahā¦ Take me back to the ā50s.
So have you used generics yourself? Roger, you mentioned that youāre currently working on implementing modules in the CUE language. Does that work call for the use of generics much?
Um, no. So I do use generics, and I quite often use them in a local way, that isnāt part of the APIā¦ There was a nice example I came across recently, where I had an interface type and an implementation that basically joined two of those together. And you want to do that in parallel. So for every method call ā and there were maybe 10, 12, 15 method callā¦ You wanted to make a parallel call to both the underlying values, and gather the results together. And without generics, you would have written a load of boilerplate code. With generics, I could write a little wrapper, and the code was really super-clean, and you could just do it in a couple of lines. Same thing for every function, regardless of the signature in the function. That worked out really nicely, actually. And not only that, you could āOh, well, okay, weāve got the boilerplateā¦ Well, maybe we donāt want to make that. Maybe we want it to be sequential and configurable.ā Super-easy.
Right. So how would you have solved that problem if you hadnāt had generics?
I would have probably just written out all the code.
Just by hand?
Probably. Yeah. Maybe code generation, but it wouldnāt have been too bad. Or maybe some dynamic type coercion. That also. But I would have had to implement a bunch of helper types probably.
Yeah. So thatās it. And I think there are those use cases where itās just perfect. And thatās why I think that I was quite pleased that they came to the language. Weāll talk a bit more about changes in Go 1.21, but I do really like the slices package.
[00:10:02.29] So for anyone that doesnāt know, this is just ā you know, thereās common things you do a lot with slices, and of course, Iāve had the case where I wanted to search through a slice, and find something based on some function, something like thisā¦ And I had to just write that manually for the particular type that I was supporting. I tried doing things with interfaces and things before, but you end up adding a lot of complexity in order to just solve that problem. So I feel like the slices package is going to help us there. Are there any other good use cases weāve seen?
I mean, I feel on the slices package this thing, tooā¦ I wonāt have to google the slice tricks document as much, because thereās some things that it covers, which Iām very happy aboutā¦ Because it was always annoying finding that thing, even though it was pretty easy to find. I was like āOkay, Iāve gotta google this thing.ā Itās nothing like Dash, or anythingā¦
Yeah. But also, the slice, you almost ā when youāre reading the code, itās not always obvious whatās happening.
So itās almost like you need to look at the slices thing when youāre reading the code as well. Whereas if itās just ā I donāt know, one of the examples, itās much easier to read, isnāt it?
So I was ā still in the slices package, I was really pleased that the sorting function there was faster. I always want to make programs faster. And we should say ā so slices will become part of the standard library in Go 1.21, but itās available right now as part of the experimental directory from Google. And I have been using it for like a year. So that change went into Prometheus using ā so where you would previously use sort.slice, you can change that to slices.sort.
Thatās much better, isnāt it? Much more of an improvement now. Iād much prefer that.
It is. You can easily see whatās going on. No, really, you donāt see it unless you look at a profile. The sort one works in terms of interfaces. So every single time it needs to compare two elements or to move things around or whatever, itās going through dynamic dispatch, through the interface mechanism. So itās doing extra lookups, like āOh, what is this thing?ā And in particular, when youāre sorting integers, which happens a couple of times in Prometheus, for instance, the generic one just compiles all the way down to the machine instructions for less than. So thereās no dynamic lookup, no function call overhead, no nothing, and itās way, way faster. In narrow, niche case, but it was night and day.
Thatās pretty cool. So does that actually happen when youāre passing a function that does the comparison of two integers? So it kind of devirtualizes the whole thing?
Yeah, so thereās two variants. Slices.sort works for things like ints and strings that you can compare with less than. And then thereās a variant which is called slices.sortfunc, where you supply a less function. And that oneās pretty good as well. I mean, itās not as much faster, but as you just said, itās calling through a reference to a function, which is much faster than doing dynamic dispatch on the elements of the slice.
Yeah, I mean, one of the things that I was interested in - itās kind of a bit of a conflict for performance optimization, because in many languagesā¦ Well, in C++ particularly, but also languages like Rust, when you have a generic type, itās all devirtualized, itās all in-lined, so everything is basically expanded out. So one thing I worry about in Go in the future is that people make something generic because of that performanceā¦ When actually it would be kind of like a nicer, easier to understand and simpler to use if it was using interfaces. Because the moment youāre using generics, you have to pass around that type parameter, although the actual type isnāt hidden under the hood, as it wereā¦ And things become, I think, quite often harder to use.
[00:14:05.17] So thereās a kind of tension there, because if people make generics truly efficient like they can be, then you have this pressure to use generic types, and then you start going down the route of āOh, things become harder to useā, and Go maybe starts to get that reputation. So Iām interested in what you think about that, Bryan, actually.
Yeah, itās definitely complicated right nowā¦ And thereās basically two cases. The case where you have some kind of method in your generic. Basically, if your generic type parameter has an interface, which has some methods on it, thatās one case. And then the case where it doesnāt have any methods, but you do want to use things like less than and greater than, and it basically has to be one of the underlying types that the compiler handles.
So right now, the first case - it basically boils down to an interface, and itās slightly worse than an interface, because the compiler is passing a little bit of extra information for the generic mechanism. So generic functions with parameters, which are interface type, are not that fast. A little bit slower than interfaces pre-generic. Whereas generic functions taking things which donāt have methods can be blindingly fast. Certainly donāt have any dynamic dispatch might enable you to in-line things you couldnāt do beforeā¦ So I think thatās already too complicated for your typical Go programmer to really grasp. Thatās really down in the weedsā¦ Sorry, I donāt want to insult anyone; I just mean thereās too much to grok, to get your head around, to read through the details of how this is implemented. And thatās just where we are today, where itās what they call monomorphization. Everything is kind of coerced to look like an interface.
I think in the future, if they do start stamping out multiple copies of the code for different types for performance reasons, then itāll get much harder to understand the trade-offs. I certainly worry a little bit about that. I guess where we are, thereās an uncomfortable thing that happens where you get advice to pass around a function parameter, and thatās exactly why slices.sortfunc has this extra parameter that we kind of donāt want to exist. And itās a value parameter, not a type parameter. In C++, that would be a type parameter. That would be parameterization on the type of the function, rather than a value that you pass into the function.
So yeah, weāve got something thatās a little bit ugly, I would say. I guess most people are just perfectly happy to get the expressive power. We should be trying to express programs nicely, elegantly; that should be our first concern. And then make it work, make it run, make it fast. Normally, the last thing you do is performance.
Yeah, my ideal scenario would be where you could use either approach. So you could pass an interface in or you could pass a function parameter in, and the compiler is clever enough to know thatās static, to know that youāre always passing the same function, and do the same thing regardless of whether youāre using generics or not. And I think it does devirtualization in a bunch of cases. Apparently, profile-guided optimization is clever enough to do that sort of thing now in certain cases, which is interestingā¦ So you know, thatās pretty cool.
Yeah, but I like that message, this thing of āFocus on making the code easy to read, easy to maintain.ā There are times when ā and if youāre lucky, youāll reach the point where performance really matters, where youāve got either massive scale, or just youāve got things that are being usedā¦ It depends on the problem, really. And then itās worth that kind of digging into the details, and maybe even worth a bit of complexity and a little bit of sort of ugliness just for that purpose. And then youāre making a trade-off for quite a good reason. But I guess, Bryan, youād recommend you profile first, you gather data, you wait until you have one of those situations.
[00:18:09.04] Yeah. I mean, youāll almost always find that your performance problems are in a few small places. So maybe itās okay to make something that was five lines of code into 30 lines, because thatās the bulk of your performance problem. But donāt do that all over the place.
Yeah. And that is tempting. I remember, I just wanted to just have the fastest possible thing. It was almost like I gamified it for myself, of just like āDo I want the best performance? Of course I do.ā And I would sometimes trade off the ā you know, I felt like Iām being clever here. Iām doing thisā¦ And yeah, it might be complicated; you have to be smart to understand it. I wouldnāt go as far as insulting half the community like you did, Bryanā¦
Yeah. And then maintaining that code over time. And where I would forget, Iād be like āWhat on earth is this?ā And then I was like āDo you know what? Iāll just rather it was dead simple. Thanks.ā
Yeah. Well, someone like Brian Kernighan said āYou need to be smarter to debug a piece of code than you do to write it.ā And therefore, if you write the code to the limit of your ability, then youāre actually not able to debug it.
I love that. That slices.sort - does it work with anything? Can you pass any type into that function?
Only ones that support less than. So ints and floats and strings. But thereās a sort func where you supply a function that implements less, if you have a more interesting type.
Yeah. So this is where constraints comes in. Sort of part of our generics is we have these quite interesting-looking ways of expressing, like, āThis is a constraint of the types that you can pass into this thing.ā And there are a few built-in ones, arenāt there?
No, in fact theyāve gone the other way. In 1.21 thereās a new package called [unintelligible 00:19:55.22] and I think the main purpose of that is to define an ordered type, which is these things that support less than. So itās in the library, itās not in the language.
I think thereās a differenceā¦ So thereās two kinds of ā you can constrain something in various ways. It looks like an interface type; a constraint is actually an interface type. And it can have methods like any interface type. So that means that youāre constrained, that that type is constrained to have those methods. But also, you can name a number of other types and say āThis interface must be one of theseā, and you just say [unintelligible 00:20:29.15] or stringā¦ And that basically means that that value must be any one of those, and if some operation is supported by all of those, then youāre able to use it in your generic function.
For example, that sort function can work with less than, because itās got a constraint that mentions all the possible underlying types in the language, of which there arenāt that many; like 10, or 15, or somethingā¦ All the uint types, all the int types, a few others. And because weāve mentioned all of those, it means we can use less than, and we can pass any of our existing types that we can compare less thanā¦ Which is - you know, thatās pretty cool.
I gave a talk at GopherCon UK last year, where I talked about using unconstrained types, and how they were kind of strictly more powerful. I didnāt talk about performance at all there. And yes, theyāre definitely less powerful. But the sort vs sortfunc example is an interesting example of that, because you can write one in terms of the other. So you can write sort in terms of sortfunc, but you canāt do it the other way aroundā¦ Which is kind of interesting to me, particularly as sort is more performant as wellā¦ Which is a bit of a shame, because weād like to be able to write the more generic, the more powerful version, rather than the other one, ideally, I think.
[00:21:59.08] But that actually made me think of ā so thereās one thing we havenāt talked about here, which I think just kind of fell out from the design, and I think itās amazingly powerful and quite interestingā¦ Itās that of generic interface types, which people donāt ā Iām not sure people are aware of quite how useful and powerful they are. So you can have an interface type that actually itself has a type parameter. For example, you could imagine a sorter, a comparer interface type that has a method that takes two parameters, both of type t, for any type, and returns boo. So thatās kind of equivalent to a function that takes two [unintelligible 00:22:35.20] but you can have multiple methods.
Itās actually a really powerful paradigm. Essentially, you can define a kind of algebra between your methods in terms of this abstract type, in terms of this type we havenāt defined yet, which is quite cool. And because itās an interface, youāve actually got an underlying value. Youāre passing this thing of type t into this interface, but youāve actually got a value under there, too. So for example, it could know how to sort. And Iāve used that a few times, and Iāve found it quite interesting. But the performance implications of it - I have no idea. Bryan, you might know - is it efficient to call a method on a generic interface, or itās about the same as calling it on a normal interface?
Methods are slightly worse with generics than they were before methods on interfacesā¦ So itās a little bit disappointing. So I guess an example which is a little bit like what youāre talking about is the heap; not the heap that you allocate memory on, but the one which sort of keeps the smallest element at the front. So thatās expressed in the Go standard library as an interface that has a less method, but also has a swap method and a pop, or a push; I forget exactly what it has. Anyway, I noticed that there wasnāt one of those in the slices package, and around about Christmas time I was off work, and I thought, āOh, I should be able to fix that in a couple of hoursā¦ā And this ballooned into something that took weeks, because itās just not that nice to try and express a thing which is a container, and has operations on the objects being contained in terms of Go generics.
Iāve got a talk at GopherCon in San Diego coming up, where I sort of explain where all this landed, which is with a completely different data structure called a loser tree. So I wonāt go into the whole explanation of that right now, but anywaysā¦ The short version is that it leaves a lot to be desired right now, trying to express a kind of a generic thing which operates as a container on other things.
Interesting. So do you think thatās a fundamental limitation of the current generics design, or something that could be addressed with a language change? Or maybe itās just because itās performant [unintelligible 00:24:51.10]
No. Well, itās a little bit of everything. I mean, kind of borrowing from something we thought we were going to talk about later, thereās a function couple of functions, max and min, that have been put into Go 1.21, and I think they form a sort of similar example. So you can write a generic ā in Go you can write a function using generics, which takes a type t, and just basically says āIf a less than b, then the minimum is a. Otherwise itās b.ā You can write that, but itās not the function that you want in the case of floating point numbers. Because in the case of floating point numbers they have this exception which is a nan, not a number; and nanās are never less than or greater than. And this is a sort of annoying anomaly. And where that story ended in 1.21, is these things became built-ins in the language. So they sort of cheated. The Kobayashi Maru for feature development.
And itās ironic, because max and min were one of Ian Lance Taylorās kind of red lines. Like, if we canāt express max and min with generics, then the generics design isnāt good enough, right? But now, āOh, dang it! We still canāt express max and min with generics, and weāre putting them in the language.ā
[00:26:08.07] Yeah. So harping back to C++ā¦ In that language you can write what are called partial template specializations. You can basically say, āWell, if itās a float (you say this to the compiler), I want you to use this version of the code. And then if I donāt say anything, just use this other version.ā And that technique, that language feature would, I think, get us out of this problem. So basically, I do think thatās the thing that would help - the ability to put special cases into my generics, and say, āIf itās this kind of a thing, then I want you to use this kind of code. And if itās this other kind of thing, then do it totally differently.ā
So this is a proposal that I made a little while ago for type switching on generic types. Itās issue #45380.
Oh, how could I forget?
But would that give you what you want?
I have to confess, I havenāt read it. I mean, maybe. Basically, what you donāt want is for the runtime to be executing these types. You donāt want to be executing these types at checks at runtime, which is kind of where you might try and do it today. It would work, but it would just be horrible in performance for anything low-level, like a sort, or something like that. Yeah, so if the compiler is doing it at compile time, that would be better. I mean, is it literally a switch, like with key statements? Is that what you proposed?
Yeah, pretty muchā¦ Except the target of the switch is the type itself, rather than a value.
Yeah, itād be interesting to try it out. I mean, all the other things that Iām familiar with in that space tend to do more of a pattern-matching approach. I guess Rust does that, doesnāt it? Iām not a big Rust user, but I think it borrowed the idea from Haskell, which sort of borrowed it from ML, which I did learnā¦ Yeah, so I think conceptually itās a little bit nicer to sort of write out the patterns of things that youāre trying to match, and the code that goes with those.
I mean, this wouldnāt allow you to do something like āOh, slice of anythingā, right? Youād have to type switch on specific types. Because otherwise, I think it might be ā otherwise, basically, youāre in inflection territoryā¦ Not great for performance.
Yeahā¦ Interesting future anywayā¦
Yeah, well, that definitely seems doable. I was just scanning that proposal, Roger, and I feel like that could be done at compile time, right? I meanā¦
Yeah, it could definitely be done at compile time, yes. One of the things about generics is fundamentally, itās all exposed ā logically, itās all expanded out at compile time, even though it might not actually be fully expanded out at compile time. You have all the information you need. You canāt dynamically generate dynamic generic types. Although, theoretically you can, except the compiler finds it out and says āNo, no, you canāt do that.ā Because you can have a recursive type, you could have a recursive type that has a type definition in there, which involves two of the original, and then calls itself, and then you get this blob of an infinite number of generic types, and the compilerās like āNo, noā¦ Not today.ā
How would people show support for that proposal? How does it work? Like, I noticed that thereās thumbs up, and thingsā¦ Do people pay attention to that?
I believe so. I mean, no oneās come out ā I havenāt seen any anyone come up with a good [unintelligible 00:29:31.29] I think they just need to have the energyā¦ The Go team need to sort of say āYeah, this is worth working on now.ā Because I think last I heard, Rust was like āYeah, for later.ā Itās a proposal hold, is what it is. Too much for now. And you can kind of do it at the moment with a dynamic type switch.
Iām surprised you yourself havenāt been put on proposal hold, Roger.
I am pretty much on hold [unintelligible 00:29:58.02] I would sayā¦
Yeah. Because Roger ā yeah, arenāt you responsible for the error interface?
[00:30:05.24] I did, I did suggest the error interface, and they saw it and said āAh, yes, this is what weāre looking for.ā Because they were about to propose the error thing ā that it just be a package that you imported everywhere. Everywhere weād have to import errors, and say [unintelligible 00:30:17.19]
Well, then itās more popular than Testify at least, until thenā¦ Oh, by the way, Iāve found out at GopherCon ā we did a panel with the Go team. Iāve found out that Testify, my package, is banned in Google.
So thatās going on my resume. What do you mean good, Bryan? Donāt you use it?
Well, I think conflict is good for ā a bit of tension, a bit of dramaā¦
Well, I could use that as a moment to shout out at qt, which is my generics-based testing package, which I quite like. It kind of has fake heritage from Gustavoās Check package, originally. But anyway, yes, it uses generics, and I quite like it, because itās small, which I donāt think you can accuse Testify that it is small.
No. I also had that same feeling, and I actually have another package, which is on GitHub, matryer/is. And that is ā I call it āTestify off steroids.ā Itās like the minimalist version, for the same kind of reason. But itās not generic, so thatās quite interesting. I wonder how.
Yeah, so this is quite nice, because if you want to compare two things - you know, for equality, or particularly for not equality, you want to make sure that theyāre actually the same type. And generics can do that quite nicely. And I quite like ā the other nice thing, I think that that is composable. So you can put these things together and you can make new checkers, which all fit into the same framework. Iāve been using it recently and Iāve been quite a bit quite happy with it. I shall post a link to it.
Yeah, weāll put a link into the show notes for that. Very cool. I was gonna ask ā oh, itās literally qt, the letters?
It [unintelligible 00:32:08.16] fairly small prefix.
Good thing we have a link, because I think people googling qt are going to find not thatā¦
This is true. This is true. Actually, I should shout out Francesco Banconi, who wrote the original Quick Test. He was a previous colleague of mine, so we wrote it together, basically.
Nice. So when it comes to like people choosing to pick up generics or not, is this sort of advice ā like, we sometimes say āIf youāre going to do an abstraction, solve the problem a couple of times before, and that really helps figure out what the right kind of abstraction isā, or if indeed there is one thatās suitable. Do we have the same kind of advice for generics? Is this a case where you think thereās a clear case for generics to just use it, or should you just solve your problems with the specific type if you only need to solve it for one type first, and make them generic later? What would be your thoughts on that?
Yeah, I think I would agree with that.
I thought you liked conflict, Bryan.
Well, yeah, I just like writing programs ā like, keep it simple most of the time. So if you just implemented one thing, then yeah, donāt muck around making it generic. Itās only if you find yourself implementing it two or three times, or you want to reuse the same thing in somebody elseās program, and it really benefits from being made generic in that wayā¦
One of the things that I really, actually, for using that pattern in Go - and it applies to both interfaces and generics, actually, is that you can do that; you can do it for one type. And actually, the changes to make it generic, the changes to make it a user interface tend to be pretty small. You can take that generic code and just like do a global substitution of the type by the type parameter, and - oh, done. Just add a few square brackets here and there and it just works. So I would say thatās a good approach, and helped by Goās syntax and semantics.
[00:34:11.06] Iāve found it sometimes takes a bit of thought to figure out what is the thing that I should be parameterizing. If Iāve sort of fundamentally got a slice of thing, do I parameterize on the thing that is the slice, or do I parameterize on the thing inside the slice? Iām not sure yet if thereās a rule there, but those kinds of questions take a bit of time sometimes. Youāve gotta maybe try it two different ways and see what happens, or start out and see where you get blocked.
Yeah, Iāve actually found an interesting case for that recently, where I was changing an API, and I wanted to change it in a backward-compatible way. And there were basically two types, both of which were kind of set ā one was type XY. So it was like a new type, but had the same underlying type. The old one was deprecated; the new one was new, but we had this function that took the old type. So of course - oh, well, you know, we want to make it check the new type. And it was taking a [unintelligible 00:35:06.18] the type parameter is foo, and itās taking *foo, and then weāll actually do a type conversion inside the function to the new typeā¦ Which technically should have worked; we were saying weāre allowing just this old type and just this new type; we could type-convert between them, but you canāt do that. But you can do that if you move the pointer out. Say your type parameter is either *oldtype or *newtype; then you can do the type conversion. So itās little nickles like that which is like āOh, thatās interestingā, where that kind of decision can make a difference.
So generally then, Bryan, would you say that you are unhappy with the performance of generics, or do you feel like in most cases ā
I think I would go as far as disappointed, because I personally, with my background in C++, I sort of expected thereād be more stamping out of different versions of the code specialized to each type, and more opportunities for in-lining, and so on and so forth. And basically, the opposite is trueā¦ Unless your type is a built-in, like an int or a float. Performance gets a little bit worse when using generics, and methods on genericsā¦ So I was disappointed by that. I mean, you know, first-world problemā¦ Having generics at all is vastly better than where we were before. But there are still these kind of corner cases that I tend to inhabit, where youāre still reaching for other techniques.
We talked about this a bit before, but is this like thatās forever because of the design, or is this sort of like over time these things will improve under the hood, and we can just wait?
Yeah, I expect it to improve over time, and particularly profile-guided optimization, I think. Trying to not get too deep into the weedsā¦ The current implementation says that anything where the layout and memory looks the same, i.e. this is always an 8-byte fundamental type, or this is always a 48-byte struct with four things in it, or something like thatā¦ Anything that looks like that will run the same code. And anything that looks the same in memory will run the same code, is the current implementation. So they could generalize that a little bit to say āWell, we run the profile. The profile-guided optimizer says there are these two cases that we should kind of flatten out into the most performant code, and then every other case is going to still run the same code.ā I think thatās eminently doable. Iām handwaving a lot of work onto whoever actually has to implement it, butā¦ I expect something like that will happen.
It kind of reminds me, Iāve gotta get profile-guided optimization plumbed into our CI pipelines, because itās been available since 1.20. I donāt think itās turned on by default in 1.21, so I really should get going on that.
What will that do for people?
[00:38:08.11] Oh, good question. Well, so first of all, the mechanism is basically that you supply the compiler with a profile, in the pprof format; that is a record of what the program was doing when you ran it doing its normal thing. So the compiler can then look at that and say, āWell, I see that 80% of the time in this program was in this one function. So Iām going to change the rules that I applyā¦ā So there are certain rules inside the compiler, for instance when am I going to in-line other functions; and it normally only in-lines really small functions. But if it sees that this one thing is 80% of the whole program at runtime, then it can say āIām going to inline a bunch more things, and Iām going to really change the rules on this one. Iām going to go all out for performance just in this one place.ā
So the Go team themselves said that the PGL, profile-guided optimization gave them a 6% performance improvement on the compiler, and their benchmarks on the Go compiler. So itās obviously case by case, but itās a little bit more work, because you have to come up with some kind of representative profile. Maybe if you only work in one environment, thatās pulled from your production environment. If you have a wide range of use cases, you maybe use benchmarks and profile that. Soā¦
Can you combine different profiles, a bunch of different profiles?
Thatās a good question. In general, there are tools that do that. Fleet-wide continuous profiling is a very general case of what you just saidā¦ And several companies sell that kind of a product. So I donāt know whether you can just sort of give six files to the compiler and it figures out what to do, butā¦ I mean, a profile is essentially a list of stack traces in the code, and sampling counts of the number of times that stack trace showed up. So you can essentially aggregate different profiles just by finding the common stack traces and adding all the counts up.
I mean, to be clear, this is applying to one main program, one binary. So you canāt sort of say āOh, weāve got profiles of a bunch of things for this particular library.ā That doesnāt apply, or is it justā¦?
Thatās a good question. I think itās matching on the kind of module name, function name, how often that shows up. So it ought to be applicable to libraries, and it ought to be fairly generally applicable. I guess the thing maybe that you donāt want to do is supply a profile thatās kind of wildly unrepresentative, because then the compiler will do the wrong thing, make your program at least bigger, which might make it a little bit slowerā¦
So if Iām supplying a module that other people are using, itād still be worth doing some PGL on that.
Oh, thatās a good question, because generally, people donāt use precompiled code in Go. Generally, theyāre compiling it all on their target.
So it wouldnāt see that if you import a module, for example.
Yeah. So in that sense, it applies more to the main program.
And would you keep updating the profile so that as things change, you keep ā
Right, yeah. That would be a good idea. I donāt think thatās vital. Like I say, the worst thing that can happen is the compiler kind of optimizes the wrong thing.
That has the potential to be interesting, because the profile-guided program itself will have different profiles, so you kind of need to iterate.
Thatās a good point, yeah. I think that itās at the margins; itās things like ā certainly right now in-lining; I think thatās the main thing that gets affected. But it might in the future do loop unrolling, for instance, based on how intensive this function is used.
Yeah, until we have an AI thatās just doing this all for us, and then we can stop worrying about it and we donāt have to talk to Bryan anymore. [laughter]
On the performance point, I know it wasnāt planned this way, but I kind of feel like having generics have slightly worse performance for that kind of interfacy case might actually be good for us in the long term, because I feel like it will make it so people donāt right now jump into just using generics, where theyāre like āOh, well, this is so much faster than interfaces, so Iām gonna use this thing instead of whatās been there before.ā
[00:42:27.07] So I feel like maybe that in the long term will help us escape the kind of just using this thing because itās faster, just using this thing because itās shiny, and it will keep us solidly rooted in using interfaces, or interfaces that are appropriate, and then āOh, well, I really do have this use case for generics, so I will use it in this place, even though I know Iām paying a performance penalty now.ā Even if it might not be true in the future. Like, I assume weāre gonna get better with generics, and then they might be faster than interfaces in the future. Or maybe weāll also make interfaces faster in some way.
Yeah, that was precisely what I was trying to get at before, actually. I do think that thereās this pressure, if itās much faster, to use generics, where it might not be appropriate. I think thatās the worry that everyone has, or many people had, about generics just polluting code because āOh, generics are faster, therefore everything must use generics.ā You know, you change io.copy, so instead of taking a reader and a writer value, you make it parameterized on the types, which could be faster, right? And it probably would be faster. So why wouldnāt you do that? But that means itās actually more complex to use.
Iām hoping that the years of people using far too many goroutines and far too many channels has taught us as a community to not overdo the nice things where we kind of ruin them.
Yeahā¦ We do hear that a lot, and we do say it a lot, and we talk about that a lot, and I do think thatās important. So yeah, thatās great. Well, before we move on to Unpopular Opinions, are there any other things coming in Go 1.21 that weāre excited about? It gets released next month, in August 2023. Min and max - theyāre cool. Clear functionās a bit weird, isnāt it?
Yeah, I was gonna bring that up. Iām happy that clear function. Itās like, I know it only saves a little bit of code, but having to write those loops over a map to clear everything out was always kind of annoying. I just want this to be empty now.
Yes. Itās weird how it does it with slices.
Yeah, it does something that you sometimes want to do with a slice; it fills it full of the zero value. But itās so different to what it does with maps. So if you have a slice that has 100 elements in it, and you canāt clear on it, then you still have a slice with 100 elements in it, but theyāre all zeroā¦ Which I think is a very, very niche case. Most people would expect is they have a zero-length slice when they finish. So I donāt really know that ā I didnāt read through all the thinking that arrived at that.
I guess itās equivalent to [unintelligible 00:44:52.19] in C, right? So yeah, itās very efficient, because you can use essentially an underlying machine instruction, probably one, to just zero it out just like in one thing really efficientlyā¦ And that might not be easy if youāre using a loop.
I feel like if [unintelligible 00:45:09.01] as well, and you just want to be āIād like all of these things to be garbage-collected, but I still want to use this slice again.ā It could be useful for that, just clearing them all out.
Yeah, itās very occasionally useful. Itās just that the same name does something so different with maps and slices.
I guess itās the same with most of those, right? Make, and new, and all of thatā¦ I guess new doesnāt, but make definitely does different things with maps and slicesā¦ Sort of, sort of.
[00:45:38.04] One thing that I am looking forward to in Go 1.21 is some improvements to generic type inference, actually. So thereās one particular ā in Go, a standard idiom is to return concrete types, but use interfaces. So youāre returning a concrete type, but youāre actually accepting an interface. But this didnāt work for generic interfaces. So you could have like an implementation, a concrete implementation, and you pass it to this generic interface, and say, āYou canāt do that. You have to explicitly mention this type parameterā, even though you can clearly see that one implements the other. And now you donāt anymore, so thatās pretty cool, actually.
Yeah, thatās an interesting point though, about āYou can clearly seeā, because thereās more typing inference that can happen, where actually when youāre reading it, you would kind of lose information. And thatās probably a line that you wouldnāt want to cross.
Itās a tricky line to choose, and they said they were conservative initially, and now theyāre a little bit less conservative. And also, if you have a generic function, it will infer the type of that generic function from where [unintelligible 00:46:47.17] So if youāve got a generic less function that automatically knows how to compare two comparable types, for example, and you pass that to something that expects another generic function, then you donāt have to mention, you donāt have to instantiate it; it will infer from where youāre assigning it to the type parameter for the functionā¦ Which is also quite cool, actually, particularly in the context of things like slices.sortfunc, and that sort of thing.
So weāve talked about the slices package quite a lotā¦ Thereās also a Maps package that sort of matches it. It has two or three functions, like keys - it gets you all the keys that have map values, it gets you all the values out of a mapā¦ Those were things you could do before you just write the loop, but those are little generic functions now that are going into the standard library in Go 1.21.
I want sorted keysā¦
Well, you can do slices.sort of maps.keysā¦
It doesnāt quite work, because it doesnāt return the sliceā¦ [laughter] Itās probably the generic function Iāve copied and pasted the most, because quite often you want to ā you know, like as a test result, or youāre printing something in a deterministic wayā¦ āI just want all the keys sorted, please.ā Like, āOh, damn.ā So just copy and paste sorted keys, and usually that strings, but not always.
I am pretty happy about the equal function, because thatās another thing that was kind of annoying to do with a loopā¦
Right. Yeah. Well, you did have to sort them then, given two maps. You had to get all the keys out, and then sort them, and then check if things were equal.
Yeah. I mean, the sorted keys - if someone perhaps hasnāt contributed to Go, maybe they could start a proposalā¦ There may already be a proposal that Rogerās written, but if not, you could write one, get involved and see what that process is like. Itās quite a nice opportunity. Thereās also clear as well; in that maps package thereās a clear function. Whatās the difference between those two?
Maybe it was there before the clear built-in?
Looking at the docs for the package, it doesnāt look like thereās a clear func in here.
Well, there was in the experimental oneā¦ And it suffered ā I mean, the whole reason why the clear [unintelligible 00:48:59.27] maps was justified was that you canāt, again, float nan, not-a-number values. They break the obvious implementation of clearing things from a mapā¦ Because a nan is never equal to anything.
Not even itself?
No, itās not equal to itself.
So if you try and delete the nan value from a map, itās like āNo, you canāt delete that, because it doesnāt exist in the map.ā
Wowā¦ Who is putting their nans in a map? [laughter]
Who would put nans in floats, right? [laughs]
Well, speaking of that, itās time for our Unpopular Opinions!
Jingle: [00:49:43.26]
Okay, Iāll go first - somebody told me that jingle is too long. Apparently, this has been said a few times; people are like āNo, thatās way too long, that little jingle.ā Itās nothing.
The singing is great.
Thanks, Bryan. Thatās really sweet. Youāve accidentally been nice to me. Actually, it was very well put together by the Mysterious Breakmaster Cylinder, who edited that and made it sound good. Itās 25 seconds long, our little jingle. Is that too long? I feel like itās the exact amount. Yeah, whatās going on?
I like it. I like that āYou should probably leaveā bit.
Thank you. Yeah. āI actually think you should probably leave. Itās gone too farā¦ā
āJust waitā¦ā
Does anyone else have an unpopular opinion?
I have an unpopular opinionā¦ Itās definitely non-techy. My unpopular opinion is that a shower is no good unless it goes properly cold.
What do you mean, you turn it cold, or you just stay in there until all the waterās gone?
Yeah, I always finish by alternating on hot and cold, and it has to finish on cold. And if it doesnāt, itās deeply disappointing. I think it was recommended by a physiotherapist once, to stop inflammation and things, and I started doing it. Now I go to someoneās house and I turned it down to cold, and itās still lukewarmā¦ Itās like āOh, no, noā¦ā I just feel bad. I feel unfinished. Itās just not right.
Do you gradually make it go cold? Like, sort of the opposite of boiling a frog. Or do you just blast it straight immediately cold?
Absolutely blast cold, blast hot, blast cold, yeah.
Yeah. I heard thatās good for your immune system as well.
Itās good for all things.
[laughs]
And lack of it is bad.
Bad for all things.
Thatās a bad start of the day.
Wow. I do like the ice pool thing. Bryan, have you ever had a freezing cold shower?
Well, yeah, when things are broken. Or itās a good example of a bad user interface, where itās a little bit too hot, and you turn it sort of a tiny, tiny amount, and itās freezing cold. Thatās my experience. I do it by accident.
I think if I have the choice between a hot shower that couldnāt go cold, or just a shower that was cold, Iād probably go for the cold one.
Iām tempted to get into cold showers, because I hear a lot about itā¦ And I used to love the plunge pools you get some times in places, where thereās just ice-cold water. You just basically throw your body in it. I find that to be really refreshing. People do all sorts of ice swimming, and things like thatā¦
Maybe my opinion will become popular with Mat in the futureā¦
Iām gonna give it a go, thatās for sure. Kris, what do you reckon?
I feel like when itās hot outside I kind of want to do more of a cold shower. Or if I get back from a run when itās been like 90-something degrees outside, Iām like āI just really would like to be a lot cooler than I am right nowā, so I feel like that can sometimes be good. And I feel like I alternate. Sometimes Iām doing a little bit of cold at the end, it sounds good. But most of the time Iām like āI just want to do a nice, hot shower.ā Also, I keep my apartment very cold, so I think sometimes I get that cold by like stepping out of the shower and itās like āOh, okay, now itās just like very cold all at once.ā
I find it weird ā if I have to have the cold at the end, I actually feel warmer when I come out of the shower. If Iāve had a hot shower, I feel colder. Thereās something about my body saying, āOh, itās cold. I want to keep warmā, and then you turn it off and itās like āOh, Iām warm.ā
Yeah, because you feel different. You feel the difference.
Your skin texture is colder, I guess, but you feel warmer.
Yeah, because the outside air is warmer. Thatās cool. Do you do any other weird stuff in the shower? [laughter] [unintelligible 00:53:42.27] No, no, fair enough. I had an ideaā¦ This doesnāt exist, I donāt think, but this should exist. And the idea was a little device you could put on your tap, and it has a blue and a red LED. And then depending on the temperature of the water, it changes, and sort of like shines down. So the water is glowing red if itās hot, and cold if itās blue. I donāt know if in every country that theyāre the two colors that people use for hot and cold. It should be, I feel like. It feels like quite universal, but I wouldnāt be surprised. What do you think of that idea? Are you in? Do you want to invest?
[00:54:24.23] Whatās halfway? Whatās lukewarm?
It puts both. Itās a kind of purple. Yeah.
It would have to be. It literally would just be a very simple ā I could get Ron Evans to build this, probably, with TinyGo. It probably wouldnāt even need that.
Trickyā¦ Electricity and water is not a great ā
I disagree. They love each other. They get very excited. [laughter] Theyāre too friendly, I think, if anything.
Your product liability people might have something to say about thisā¦
Well, thatās why I donāt hire those people.
I do feel that thereās sometimes electricity in that, because you know, you have those obnoxious handsfree faucets that have to have some amount of electricity for the sensor, or whatever. So itās kind of like that, itās just adding some LEDs instead of some sensors.
Yeah. Iāve got one of those taps that does immediate boiling water, which turns out eventually good, because youāre not boiling a full kettle. If you want a cup of tea, you can just do it straight from the tap. But then I think āI want that tap in my bath as wellā, so I can just ā
Scold yourself. [laughter]
Yeah, wellā¦
Yeah, product liabilityā¦
So you donāt want to invest, Bryan. Thatās what Iām hearing. Yeah, fair enoughā¦ Hopefully it does really well then, and youāll be like āAh, I was the guy that missed out on the LED taps.ā
Well, I have often thought that a hedge fund which the investment strategy was just exactly whatever the opposite i from whatever Iāve invested in, that would be a great product.
Yeah, thereās another idea I had when we redid our kitchenā¦ And I wanted to, instead of cupboards, just have dishwashers. Just every cupboard was a dishwasher. And you just put your dishes away, it just cleans them, they stay there, you donāt have to pack them awayā¦ [laughter] Imagine how much time youād save. And I pitched it to the guy that was designing the kitchen. I pitched it as though I was dead seriousā¦ And he was sort of contemplating, and then they just said itād be really expensive and wasteful to run.
And you probably donāt want to wash your cereal boxes, right?
Oh yeah, thatās true. You want other ā thereās other things; well, you could just not turn it on. [laughter] But yeah, thatās a good point.
You can cook salmon that wayā¦
Is that what you do, Bryan?
Just donāt put the soap tablet in.
Donāt put detergent in, yeah.
Yeah. Weāll put like a dressing in instead.
Wrap it in foil. Two layers.
Have you ever done that, Bryan?
Iāve heard this, too.
It makes sense.
Iām not gonna try it eitherā¦ [laughter] If youāve got a huge salmon, itās quite difficult to ā you know, itās not gonna fit in your oven, right? So I could see why people might want to do this.
Yeah. You could take the drawers outā¦ I bet you could cook clothes, and stuff like that. What are we doing? Weāre wasting our time. [laughter] Noā¦? [unintelligible 00:57:11.17] Kris. How do you cook salmon, Kris?
I donāt actually ā I donāt eat seafood, so I donāt cook salmon at all.
Right. Thatās what I mean, Iām sure you could cook other stuff.
Easy answer.
Also, I donāt know if my dishwasher is that much bigger than my oven.
Oh, really? Have you got a small dishwasher, or a big oven? They do tend to be smaller, donāt they?
And you might not necessarily be able to pull all of the racks out of a dishwasher, depending on what type of dishwasher it is. It might get a little mad at you. Theyāre very intricate machines, very magical.
Yeah, theyāre clever. Theyāre good. Iāve got one which at the end of its cycle, it opens the door, it pushes the door openā¦
[00:57:54.02] Ours does that, too. Yes. Itās weird when youāre in the room and youāve forgotten that itās on, and you hear that [00:57:56.09].
Yeah. I love that.
If anybody wants a good watch, thereās a guy on YouTube that has not one, but two whole videos on dishwashers and how they work. Thatās not just like a five-minute; these are two hour-long videos on how dishwashers workā¦ The channel is called technology connections. And itās one of those things where youāre like āThereās no way Iām gonna watch this whole thing.ā And yet, you will watch the whole thing. [laughter]
Does it cover cooking of salmon, and other fish, orā¦?
No. But he does scold people for pre-washing their dishes.
Yeah, we need that in the show links, please.
Yeah, letās do that. Weāll put that in the show notes.
Yeah. You learn to not pre-wash your dishes, and not use pods. You should just use like the cheapest detergent you can get, because itās just soap, itās all the same.
This is goodā¦ The pods are actually worse, unless you use multiple of them, because thereās a nice little pre-wash cycle, andā¦ Itās a good video, just go watch it.
What about rinse aid? And by the way, when he scolds people, does he use one of those taps that does the water, boiling water, quickly?
Noā¦ He just looks at you as if heās a disapproving fatherā¦ Which might be the same. It might burn you in various ways.
Thatās how Bryan looks at me.
Bryan, did you think of an unpopular opinion?
Oh, you mean beyond cooking salmon into dishwashers?
You expressed no opinion on thatā¦ [laughter]
I wanted to rant about ā just a little short rant about people who seem to want to put the entire program in one line of code. They get the data, and then they filter it, and then they decorate it, and then they map it into something else, and then theyā¦ Maybe a little bit more in the JavaScript world, or the Python world; itās a little bit more pop ā but I see it. People trying to get that into Go. Just write the loop, please. Just write the thing that does the thing. Donāt try and put it inside of ā it doesnāt make it any better if itās in a function in a different file. I just have to go read that.
Is this another reason why slices.sort should not return the slice thatās sorted?
Because that enables you to kind of [unintelligible 01:00:08.21] Iāve got this thing, it returns a slice, and itās sorted, and I can have them all in the same expression, deeply nested, sort, filter, blah, blah, blahā¦
Yeahā¦ Well, so I guess the implication would be that it should return a different slice. Whereas the one where it doesnāt return, the implication is it mutates the one you gave it.
Iād say donāt be scared of vertical white space, right? People want to put it all in one line because it looks look simpler, because itās all in one line. But actually, just have a few different lines. You can have a comment.
Yeah. You see, that pattern you see happening with ā Iāve seen it now inā¦ I did a bit of Svelte.js, which is a JavaScript frontend frameworky thingā¦ And the way that they recommend you format your code - having attributes inside an HTML tag, on different lines. And it really ā when you first see it, you think āThatās really unexpected.ā Itās very common to just have them going horizontally. But itās so much more readable. So yeah, itās like, thatās what I do. And actually, a lot of the formatters do that as well.
I do that with Go function parameters, actually, a lot. Actually, if itās just starting to get a bit long, I just put every parameter on its own line, open brackets on its own line, each parameter separately, close brackets right at the end, on its own line too, and it works quite nicely.
Much more readable. Itās also nice because they line up; all the variable names are aligned in a little stack, which is great.
Yeah, itās great.
But this is not popular opinions, this sectionā¦
[laughs] I feel like with the Code Golf community it will be unpopular. Theyāre trying to minimize on lines, and characters, and all thatā¦
[01:01:54.10] Yeah. Iām relying on there being a lot of people who like the idea that they can write the whole thing in one line.
I guess that the sort of idiom that youāre ranting against really is maybe epitomized by the sort of fluid programming styleā¦ Or fluent, sorry. Where you have one thing, it returns the same thing, it returns the same thing, and youāre just kind of operating on that thing flowing through, so you donāt ā yeahā¦
Yeah, people do that to create little DSLs, and thingsā¦ And I understand the appeal of it, but almost in every case I find it to be I would rather it was just spelled out in the boring way. Itās just very easy to ā itās much easier to debug things. You can put log statements in between, and things like this as well, rather than being ā yeah. And I think sometimes package developers - they want to really help the people that are going to consume the package, so they do a lot of things, like a lot of extra help, and a lot of work for themā¦ When actually you arenāt necessarily helping. You might as well just let them ā you know, theyāre not idiots. Let them do their thing. You donāt have to solve every problem.
Yeah. Hard to argue against, when youāre in the design phase and theyāre like āOh, but this will make it easy for peopleā¦ā I donāt think so, but itās a tricky conversation to have, I think, sometimesā¦
Yeah, yeah. I think so.
I have an unpopular opinionā¦ I feel like it might actually be ā maybe this time Iāll actually get an unpopular one.
Humble brag.
I do have, I think, the second most unpopular opinion everā¦
What was that one?
I think it might have been the one where I said āCalling Go Golang is like deadnaming somebody.ā
Oh, right.
That was very unpopular. People were very mad at me about that one.
Thatās popular with me.
I think itās popular with a certain subset of people, butā¦
So yeah, my unpopular opinion - itās about analogies. I think that the tech debt analogy - we should get rid of it, because I donāt think the thing that weāre talking about when weāre talking about tech debt is debt. I think itās more akin to malpractice, and people are being irresponsible. Because I think most of the time when tech debt gets brought up, itās like āOh, weāre just gonna skip writing the tests, or skip writing documentation so that we can get this thing out the door faster. Or weāre just gonna code this in like a really messy way, so it gets out the door faster.ā And Iām like, āThatās not debt. Thatās you not doing your job properly. Please just write the comments, and the dots, and the tests.āItās part of the job. You canāt cut out vital things. Or if you do, then youāre committing malpractice, and we should call it that, and thatās why I think itās gonna be unpopular. So itās not tech debt, itās malpractice.
Do you ever though make technical decisions that are pragmatic? Like, there are ways that ā I donāt mean skipping tests. I mean, I do TDD, so I rarely skip tests, and docs; I think thatās all very important. But do you not sometimes think, āWell, this thing could be better, but weāre going to just ā itās good enough for now, and weāre gonna ship it. But then maybe at some point we have to come back and fix this upā?
I think if you have a good understanding of the trade-offs, and itās not like a ā like, I guess itās about how much future harm are you going to do in this, and also how much is it of a best practice thing? Like, if youāre skipping best practices, then obviously you shouldnāt be doing that, so itās not really debt. But I think a thing that might be akin to technical debt is choosing to use a library or framework instead of building it yourself. So itās like āOh, Iāve assessed how long it would take us for us to build it, Iāve assessed the risk of taking on this dependency, and actually using this framework, and all of the knowledge thatās needed for both options, and weāve decided that taking on this framework makes more sense, even though itās more risky.ā I think thatās closer to ā especially the way businesses use debt. Businesses arenāt just going out and being like āIām gonna go get a big olā loan just for the hell of it.ā Itās like, no; youāre gonna sit down and assess what are you actually going to use the money for, how are you going to use it, how are you going to repay it, all of this stuff.
[01:06:03.13] So if youāre doing all of that math and risk assessment, then what you are doing is likely a debt-focused thing. But thatās rarely, if ever, at least in my experience, what people are doing. Theyāre just kind of not doing the things they should be doing, and then being like āOh, weāll just fix it later.ā And then later literally never comes, and then they just throw out the whole thing, and theyāre like āOkay, weāre gonna do it right this timeā, and then they do the same thing again.
I guess the thing I think itās more akin to is using single-entry accounting for your multimillion dollar company, and then having no notes in your single-entry account. āMoney is going places; where does it go?ā āWe donāt know.ā Itās that level of thing. And itās like, how do you clean up a single entry accounting system and turn it into a double entry accounting system down the road?ā Itās like, thatās going to be awful for you. You should never do that. If you know youāre going to build a big enough business where youāre going to need double entry accounting, just start with it. And itās the same thing with this. If youāre not building something, youāre gonna throw away in six months, then just write the docs, just write the test code; think about what youāre doing. Itās gonna make you go faster in the long run. Youāre not gonna get that much speed if youāre like āOh, Iām gonna do this, because itās gonna save me like a few hours here.ā Itās gonna save you a few hours here, itās gonna make you spend four weeks trying to unwind it in like six months, or less.
How to feel about that? I agree.
For me, a lot of the tech debt ā Iād say the biggest tech debt things that Iāve seen in the past have usually often been because youāve made a new API, for example. Youāve made a new API, and you canāt remove the old API, because people are using it. So you end up with two versions of the API. And at some point in the future, you realize that no one is using the old API anymore. But removing it ā maybe youāve written it in such a way that itās really hard to remove the old one. But you kind of want to, because itās holding you back, because itās using loads of stuff that you want to be able to get rid of. So thatās tech debt to me. Youāre in this situation of being indebted to this thing of the past, which you kind of had to take on this debt, and you kind of have to pay it sometime. Thatās often the case Like, not just skipping tests. Thatās an easy ā āYeah, weāre taking on this. Weāre committing malpractice by deliberately taking on this debt.ā I suppose. But thereās loads of other cases, I think, where it just arises, because [unintelligible 01:08:29.19] pragmatism, because you have to do this this way, otherwise you wonāt make progress.
Yeah. And I think, once again, if youāve done a lot of measured analysis of things where you go into it and youāre like āOkay, this is why weāve taken this onā, I think it can be described as a debt. But I think a lot of the times when people are doing it, theyāre not winding up in those situations because of ā I feel like a lot of times, at least when Iāve walked into places, itās like weāve wound up at those places not because people have thought things through, but because they just rushed to do something. So itās like āOh, well this thing is hard to maintain, so weāre just going to greenfield it.ā And itās like āOkay, but whatās your plan to actually deprecate and dismantle the old thing?ā And itās like āWell, we didnāt think about that.ā Iām like āWell, okay, thatās notāā Once again, weāre back in the realm of - just because you have itā¦ Like, you have it now, and you donāt like that you have it. Well, you have it because you didnāt plan to actually get rid of a thing, but you knew you had to get rid of the thing. That doesnāt feel as much like responsible debt usage to me. That, once again, feels like āNo, you should have planned for how youāre gonna get rid of it if you knew you were gonna get rid of it.ā
Obviously, if you need to build this new API for some reason, and youāre like āWe donāt know how weāre gonna get rid of the old one, and weāre marking that down as a debt, and we know weāre gonna have to deal with it, and itās not gonna be painfulā - different situation, right?
But we know how to get rid of it. Itās just gonna take two man months of work, and we donāt have that time. Thatās usuallyā¦ We know how to do it, we know exactly what we want to do, but we just have to pay that debt.
Kris, I bet your finances are in great shape, arenāt they?
Yes. [laughs]
Yeah. I thought so.
Iām the person that was like ā to my friends, Iām like āYes, I balance my checkbook every month.ā And my friends are like āWhat do you mean balance your checkbook?ā Iām like āI reconcile my financesā¦ What do you mean what do I mean?ā
I was also the person who was 21, at the bar, just like keeping diligent track of my drinks and how much I had spent, so I would know how much money I had spentā¦
Even while very drunk, I would do this. Iād be like āOkay, Iām just documenting allāā Iād wake up the next morning and be like āOkay, well, I guess thatās exactly how much I drink. Okay.ā And then you look at the credit card, itās like āOh, yeah.ā So yes, I keep very good track of my finances, yes.
You mean you actually count your change.
I mean, I donāt spend cash anymore, so not reallyā¦ Or I rarely spend cash.
I donāt even look in my bank account. Iām basically the opposite of that.
Itās all gone, Mat.
Yeah, basicallyā¦ Okay, I have another unpopular opinion, another one. A quick one. I get this ā we obviously want to be nice and kind to everyoneā¦ But actually, in the right places, banter, being mean, poking fun is the way Iāve built my strongest friendships with people. So I actually think that itās not as simple as just always be kind and nice to everyone. I think itās an intellectual exercise sometimes, tooā¦ Especially if you do it in a way thatās funny, and somewhat uplifting. It can be. So I just donāt think ā my unpopular opinion is donāt always be nice to everyone, because you miss out.
Be mean to your friends, is that what youāre saying?
I mean, I basically am. Kind if. I would hate the idea of upsetting anyone. And I do do that, because thatās a risky take. One time - this is quite embarrassing, but Iāll tell this quick storyā¦ I was introduced to this guy, and he had a very cool ā the way he was dressed was very cool, but it was deliberatelyā¦ Almost like dystopian. He looked dystopian in his whole vibeā¦ Which I really appreciated. I thought he looked great. So he had really sort of tatty clothes, and like scruffy hair, and stuff. He looked great. And then someone introduced him and said, āOh, this is John.ā And I just said, āDidnāt I give you a pound earlier, outside?ā And I donāt think he liked it.
So thatās one of those things where Iām drifting off to sleep and Iām suddenly woken again where Iāve said this horrible thing to somebodyā¦ Take a risk; sometimes it doesnāt pay off. But to the right personā¦ Like, if someone said something like that to me, Iād be thrilled. And I do get it. At the conferences - I was at GopherCon EU recently, and someone said to meā¦ Last year someone said ā because I talk about my hairline a lot. They said āYour hair doesnāt look that bad from a distanceā¦ From a distance.ā Itās like, āYouāre quite good-looking in low res.ā Iād be gorgeous if I was a Minecraft characterā¦
And then this yearā¦ This year someone said ā because theyāre joking; they feel like they know me, and itās a complete stranger, but they just said āIs that a wig?ā Why would I choose this?! [laughter] Imagine going into a wig shop and saying āOh yeah, how much is that one? Very affordable. I thought it would, because itās tiny.ā
They clearly thought your hair looks good. I cannot think why, yeah.
Yeah, exactly. It doesnāt look ā itās not great. Itās not great, butā¦ So yeah banter and ā what do you think?
The thing you said about the low res reminds me of that āCute from far, but far from cuteā line, which is always like funā¦ But I donāt know how much I disagree with you, because I think in some spaces there is this very large sets ā I think especially within tech companies now, thereās a very large sense of āYes, be nice to everybody, be kind, be civilā, all of that.
[01:14:11.02] And I think of like the like black or queer spaces that Iām in - like, people are notā¦ Like, thatās not how things work there. Weāre mean to each other all the time. This is not like all people in this community, but a lot of people; itās where the whole like throwing shade comes from, reading people, all of thatā¦ Itās just like this - yeah, you kind of read people [unintelligible 01:14:29.09] sometimes. Youāre just like āYeah, youāre still my friend, but what you did - Iāve gotta rip you apart for that.ā
And I think thereās also this slight level for me where ā I donāt particularly like when environments try to be kind to everybody, be nice to everybody, or āWeāre welcoming to everybodyā, because thatās like a little bit of a dog whistle for me that itās like āIām probably not in a safe space.ā To be blunt, I guess itās like āThis is some white people nonsense when that happens.ā We have to recognize that sometimes people are gonna not be nice, and what are you going to do then? Are you just going to tell them to be nice? Thatās not how this works. Who determines what is nice? Is it you that determines whatās nice? Because what might be nice for you might not be nice for me. So I think thereās a lot of complexity in there. But I think overall, Mat, I agree with you slightly.
Yeah. I mean, those roasts, when they do the comedy roasts of peopleā¦ Iād love to be doing that. Maybe we could have that as a regular segment. Like, āTodayās the roast of Bryan Boreham.ā [laughter]
[unintelligible 01:15:26.06] the whole episode.
Yeah, itād be a new series, that one. [laughter]
But I was listening back to one of the episodes - I think it was a Gophers Say episode where you were hosting, Matā¦ And all of us were just like roasting you for like the entire episodeā¦ And that was fun.
Yeah, exactly. Yeah, it was fun. But I think you miss ā if you have this very sterile environmentā¦ And I understand why this happens in tech companies; of course, we want to make sure that people arenāt ā like, you donāt want to upset people. But you miss ā thereās a missed opportunity there to build some strongerā¦ Itās a little bit like a cut, where you get scar tissue on a cut, and itās stronger. That scar tissue is stronger than the tissue there was before. So these little cuts, these little jibes - I think we need it.
The more you explain this, the more Iām like āMaybe [unintelligible 01:16:20.22] Because I think too part of the issue I have with the āJust be nice to everybodyā is like, is that really the biggest problem you think we need to solve right now? Itās just like, people are saying mean things, and Iām like āThatās not the biggest problem that I have certainly had in a lot of these tech spaces.ā I would just really like it if people werenāt doing racist things all the time. And itās not them saying things, itās like other things. So I think sometimes we focus a little bit too much on the āOh, just say kind things to each other, please.ā
Right. Yeah. Itās almost worse by just āNow at least weāve solved this problem, because weāre all saying these right things.ā
It reminds me a bit of a few years ago, when there was a really big push to get rid of certain words that we use in tech, like whitelist, and blacklist, and master, and all of thisā¦ And people are like āWell, itās really painful for people of color to have to see these words, and all of this.ā And Iām like āBlack people were just like ā what do you mean?ā Like, seeing the word āslaveā is not throwing me into an existential crisis, or anything. Itās a thing that happened. But also, this usage of master, is not different; whitelists and blacklists have different ā like, words can mean multiple things. So itās like, this feels really weird as a thing for us to be focusing on right now, especially when itās like, there are much bigger problems that we should probably be looking atā¦ And there was like a non-insignificant amount of effort that went into āLetās go through all the codebases and remove master. Letās go through all the codebases remove blacklist, and whitelist, and all of thisā, and I feel like after that people were kind of like ā itās kind of like after the election of Barack Obama, like āOh, no more racism. We got rid of all the stuff.ā But it was like, āThatās not the stuff. Thatās not the thing.ā I think itās kind of the same with this āOh, everybodyās being nice and civil and kind to each other right now, so thereās clearly no problems with other stuff.ā Thatās not how that works.
Yeah. On a level, yeah.
But Roger, youāre quite a nice guy. Are you ever mean to people?
Never. [laughter] Only my friends.
Exactly. Your closest friendsā
We definitely have some good banter, yeah.
But you mentioned this, Kris. Sometimes ā I mean, I think itās really valuableā¦ A joke thatās a jibe can be a really kind of good way of actually people getting some feedback. Like, Iāve actually ā you know, thatās how we do it. If someone ā if theyāre being big-headed or something, the punishment, the social kind of reaction to that is often a joke, or poke fun at it, or something like thatā¦ And itās kind of a nicest way, or a very nice way, in some ways, to deliver that bit of feedback. And itās kind of light-hearted, and itās non-serious.
Many a true word is best said in jest, right?
So it might sound like banter, but youāre actually being mean.
Well, I think itās sometimes a good signal. And it gets you thinking. But itās a safe way to do. Humor is often a safer way. Bryan, you called a lot of people idiots today on this podcast, so I assume youāre on board with this. [laughter]
Individually, by name. Yeah.
Yeah, weāll cut it out. Weāll cut out all the names. Thatās brutal. [laughter]
Iām just sitting here thinking that there are a lot of cultural differences, and that really in a bigger company tends to be a thing that you need to watch out for, and in a broadcast medium you have to go to the lowest common denominator. That makes it harder. But I do love the sort of ā well, for meā¦ Now Iām going to insult more people. So the sort of American thing of āEverything is awesome!ā All of the āFantastic!ā If itās not fantastic, then you must hate it. You know, āHey, I fixed that bug.ā āFantastic!ā Right? And the British thing is more āYeah, itās alright. You could do better. Yeah, fair. Yeah.ā And I really love many of our Eastern European colleagues who just say āThis code is s**t.ā [laughter] Theyāre just absolutely straight out with ā for the same code, to be clear, in each case.
Yeah. I feel to Eastern Europeans, the highest compliment they can give is like āGood. Itās good.ā And youāre like,
āOh, okay.ā [laughs]
Once every five years, yeah.
But the other thing going around to conferences and stuff Iāve noticed is that because in a way weāre all selected around this language, so weāre all kind of in software, a lot of us like building thingsā¦ So I think thereās a certain level of ā I donāt know what it is; thereās certain level of intelligence you can kind of assume with technical people. Or itās whatever the Go community does that attracts people to it, I donāt know. But I find that wherever I go, some jokes just work everywhere. And that was a big surprise to me, because I was very conscious of different kinds of cultures, and different approaches to things. But I do find that you can kind of have ā we just have a lot of fun with people. Anytime Iāve interacted with groups in the Go community, in tech communities, it tends to be a really high level of kind of really good, quality sort of interacting. Only sometimes ā well, like I said, people make fun of my hair, because I make fun of it on stage, and stuff. But itās fun, itās nice.
[01:22:10.15] So what kinds of jokes do go down well, universally? Iām interested, given that Iām giving a talk at [unintelligible 01:22:14.14] in Italyā¦
Yeah. Well, in the conference audiences, a lot of them listen to Go Time. So thatās different, because they sort of expect it now. One of the big things I noticed is you have to let people know that itās a joke. You canāt just say something thatās hilarious, that we might think itās hilariousā¦
Arguably hilarious.
Yeah. But if they donāt know itās a joke, theyāre probably not going to just sit and laugh at you, because they might consider that to be quite rude. So standard office humor works at conferences. I donāt do it, but things like āOh, forgive this code. I wrote it on a Monday.ā That will get a laugh. Or if you say, āOh, I probably did this before Iād had any coffeeā¦ā These sort of things work, because theyāre safe. Theyāre a bit like - we have these Christmas crackers in the UK, and they always come with a little joke that is just terrible. Theyāre terrible jokes. And itās almost like youāre united in the eye-rolling against these jokesā¦ But itās safe, they know itās a jokeā¦
I said once at a conference that my dad had said, āOhāā Yeah, heād said something that I canāt remember what it was. And I just said, āGet out, dad.ā Right? That was my thing. Which, to me, that was really funny. And it was just silent. Everyone just thought I was telling my dad to get out. So itās like, it sometimes doesnāt work.
Yeah, I feel like the broader thing is just youāve gotta have a lot of nuance with this, right? I think sometimes in these types of spaces, or in communities, or I guess in the world in general, itās like, people want to have one easy way thatās like universally true, objectively. Like, āEverybody should be nice to each otherā, or kind, or these other very positive words. And itās like āWell, I mean, thatās not possible.ā Thereās gonna be some people who are gonna be not nice, or not kind. But itās also just infeasible, since what is nice from one personās perspective is not nice from another personās perspectiveā¦
Thereās the whole thing about Southern people, where if they say āOh, bless your heartā, itās like āAre you saying that in a nice way, or are you saying that in like the ānice wayā? So itās like, the very same words, said in the very same way, could mean two completely different things. So I think itās more like weāve gotta be like, letās navigate these situations better, and letās have ways of like, if there is harm thatās done, repairing that harm. Focus on that, and making sure that itās like āOkay, thatās a line weāve crossed. Letās make sure we donāt cross that line again.ā But I think when people start getting into the dogmatic universality of like āDonāt tell jokes about thingsā, or donāt do this, or donāt do that, itās kind ofā¦ I donāt know, thatās a little too much; this pendulum has swung a little bit too much to the other side.
Yeah. And we should forgive people as well if they do cross those lines, especially if itās a joke. It depends, but if itās coming from a good place, and itās too far, or whatever, I do think we need to be a bit more forgiving, rather thanā¦ I sometimes get DMs, and itāll just say, āMat, no.ā Itās just like what you might say to a dog. So I get that, and Iām just like āAh, come onā¦ā
I donāt like the concept of throwing away humans, or like being like āYou did something bad. Youāre gone forever.ā Itās always irked me a bit. Even with things where Iām just like āI donāt like you as a person at all.ā But stillā¦
Yeah, you still do a podcast with me.
Iām not saying you specificallyā¦
Oh, right. Not this time.
ā¦Iām saying āyouā in the general. I mean, I find ways to poke fun at youā¦ I made a whole little TikTok about you, that maybe one day will get posted, because I think itās hilarious.
[laughs]
Yeah. Weāll put it in the show notes.
Iāll install TikTok for that. [laughter]
Oh, a plug - we do actually have a TikTok. I found out. Iām on the TikTok. I didnāt know. I thought it was just like I never had anything posted about me on TikTok, but thatās a lie. Thereās lots of videos on me on TikTok.
Oh, wow. I didnāt know that either.
Go check out Changelog.com. Itās like @changelog.com at TikTok. Weāve got a nice little TikTok page.
Oh, wow. Nice. Okay, well, on that bombshell, itās time for us to wrap this up. Weāve gone way overā¦ But this was great. I hope theyāll keep this in. Thank you so much for joining us to talk about generics. Roger Peppe - always a pleasure. Hopefully youāll come back again soon. Bryan Boreham - again, we should maybe do some more performance-specific episodes. That would be really great to talk to you, pick your brains on that a little bit more as well. And of course, Kris Brandow. Thank you very much, see you next time on Go Time.
Changelog
Our transcripts are open source on GitHub. Improvements are welcome. š
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK