7 ms·
How would you write a singly linked list who’s contents are arbitrary? What if you were to map a function over it? Say you want to use this data structure with
by puddingforears 5y ago
How would you write a singly linked list who’s contents are arbitrary? What if you were to map a function over it? Say you want to use this data structure with third-party objects? How do you do that right now?
- Taek 5y agoFind a different way to solve the problem. I've written close to half a million lines of code in Go and the lack of generics has been a pain point in maybe 1% of that? Usually, if you are thinking about generics you are reaching for abstraction when you don't need to be. If you really need generic structures you can use the interface type but generally there's a simpler solution that doesn't require generics.
- tengbretson 5y agoMaybe you could have gotten that work done with fewer than 500,000 loc if you used a language with a better feature set.
- jshen 5y agoAnd it would have been far harder to read for those new to the generic code base. Complex abstractions make people feel smart, they rarely make code easier to understand or maintain.
- aptenoforst 5y agoHow is a generic data structure a COMPLEX ABSTRACTION?
- jshen 5y agoThey are complex. I’m guessing you haven’t thought about them much beyond the trivial use cases.
- h4x0r12345 5y agoNo, it's relative. For the top 5% - 10% of developers, generics are a useful tool for doing their job efficiently. For the bottom 50% of developers, generics are complex and confusing, and only provides more footguns.
- citrin_ru 5y agoFor 0.5%-1% C++ is a powerful tool which allows to quickly (thanks to rich abstractions) to write high-performance code. For merge mortals it is a tool hard not to misuse full of hidden traps and debugging of code written even by the very best developers (surprise - it has bugs too) is a challenge. Go just did a step towards C++, even if a tiny one.
- pjmlp 5y agoNot everyone is entitled to be a sushi master.
- Taek 5y agoAnd the top 1% of developers know that you are most productive when you stick to the simplest primitives ;) I jest, but I also don't. All the best developers I know strongly prefer footgun-free libraries and primitives. The advantage is that you don't _need_ to spend brain cycles checking and double checking that it was written correctly, and when you want to make changes you don't need unwind an elaborate abstraction to stretch it further. In martial arts (I'm a second degree black belt), the third move you learn is the round house kick (turned leg kick - the first two moves are the punch and the straight leg kick). At the olympic level, 70% of all points are scored using a roundhouse kick. The other funny thing about the roundhouse kick is how much you can learn from watching someone do a single one. You can tell the difference between someone with 2 years of experience and 3 years of experience, and you can _also_ tell the difference between someone with 15 years of experience and 20 years of experience. The point of this story being that masters are masters not because they can do elaborate techniques, but because their command over the simplest techniques is superlative. I've found in life that this applies to pretty much everything. Martial arts, programming, painting, cooking, and effectively any task that definitively has some people who are better than others.
- theshrike79 5y agoIf people would stick to common generic data structures (like a map/list that can handle any datatype), i'd be fine with abstractions. But some people have a tendency to play code golf with their codebases. I have, for example, encountered a "generic data structure" that looked like a normal linked list on the surface. BUT, it actually sorted the largest three items in the first 3 cells and the average in the 4th. That was multiple days of work wasted because someone decided to be cute with their data structures. And that wasn't even the only one of such "generic" monstrosities in the code.
- h4x0r12345 5y agoGenerics (and other abstractions) are not the root cause. Go was a pragmatic defence against mediocre developers. The majority of developers are mediocre by definition, and will abuse _any_ abstractions to create Rube Goldberg contraptions and monstrosities.
- pjmlp 5y ago20 years ago those mediocre programmers were using Visual Basic and Java, so look for the past to see where future goes.
- bmn__ 5y agoSo blame goes to the hammer instead of the carpenter?
- carnitine 5y agoWhat does that have to do with generics? Surely they’d have written the same bad code monomorphised?
- Fire-Dragon-DoL 5y agoWell there is a valid point of abuse in abstractions. The ruby world is a disaster because of the power provided combined with people reaching out to all sorts of abstractions the entire time for purely experimental reason. It's true that applicative code shouldn't need generics in probably more than 90% of the times, however the lack of it affects library authors quite heavily
- fiddlerwoaroof 5y agoOptimizing for people that are new to a codebase seems like a mistake to me: onboarding costs are relatively minimal and finite (per developer) whereas maintenance costs have no fixed bound: if generics let you exclude invalid states by design (and they do: this is one of the biggest advantages of parametric polymorphism vs. interfaces), they will be useful for keeping maintenance costs under control.
- jshen 5y agoI’m guessing you like Haskell and similar languages, because that’s the natural conclusion to your line of reasoning. I don’t agree with you, but I could be wrong. There are plenty of languages that are aligned with your point of view. I like go because it was going a different direction, and I hope that doesn’t change. You can use Haskell, scala, typescript, etc to get what you are looking for.
- Taek 5y agoYou definitely want to optimize for people who are new to a codebase. Over enough time, the codebase grows to a point where essentially _everyone_ is new to each area of the code, because nobody has touched that code in 2-3 years and the person who wrote it may not even be with the project anymore. Even for your own single-person projects - if you get fancy with the code, 6 months later you find it's a lot harder to get back into and mess around with than if you had written the code as though you were presenting it to a beginner.
- fiddlerwoaroof 5y agoYou want patterns that are well-known to the maintainers, but this is different from “optimizing for the new”: consistent idiomatic use of a library like XState or Ramda in a JavaScript project can cause a high onboarding cost (because the new developers don’t know the library well) without any corresponding ongoing cost.
- erik_seaberg 5y agoManagement is responsible for making sure that doesn’t happen, by retaining experts and demanding documentation and investing in ramping up new experts. Making the code bigger because each line does less is not going to save us from nobody understanding prod, and a short learning curve puts a low limit on the value of our staff (who quickly run out of tools and stop improving in clarity and productivity).
- sterlind 5y agoso as an example, I've used priority queues a lot. you need them for Dijkstra.. apparently golang has a heap package which lets you push and pop `interface{}`. sure you can cast, and I guess people have to, but why couldn't Go just call `interface{}` object or any? the awkwardness of the convention suggests an unwillingness to accept failure.
- xh-dude 5y agoParametric polymorphism is a better fit for container types IMHO. There are some interesting notes here… In Go prior to generics, interface{} is an escape hatch less frequently needed but not necessarily much safer than void*. Post generics, interface{} is suddenly more useful and will be aliased by ‘any’. The way the std lib heap works in Go, an implementation doesn’t have to mention interface{}. Using the Go std lib solution is about satisfying a few interfaces, defining some methods for sorting and swapping over the element type. The use of interface{} is internal. Go’s generics solution is going to have type constraints, which I think will be very familiar to some and probably new to others … So, the Go generics PQ should still require some constraints on elements, not ’any’thing will work. I’ve really enjoyed constraints in languages and it’s not quite natural in C++/Java, but Go’s interfaces already do some ‘constraint’ work conceptually and can be used as constraints in Go’s generics syntax. I’m interested to see how this plays out.
- jacobvosmaer 5y ago>not necessarily much safer than void* You can cast void* to anything you want. With interface{} you get a type check, either through an assertion or a panic. That is a big difference in safety.
- xh-dude 5y agoFair point. Maybe there are contrived cases that can get nasty (an interface{}-typed variable boxing a function is possible, not so with any non-empty interface ), but in practice the pathology would be ‘panic’ more than ‘here are the keys to the exploit kingdom’, if this is what you were thinking. I was thinking more about silence where someone expected a greater degree of compile-time type safety than they really had, or relatedly e.g. the subtleties in JSON encoding / decoding where there is silent data corruption that could fall through the cracks - mostly I feel like I avoid these things by not using interface{}; I certainly did not grasp that without some experience with the language.
- Taek 5y agoLines of code is a complete red herring. It takes me less time to read and review 500 lines of Go than it does 100 lines of JavaScript. Sometimes - especially in other languages - you see a piece of "elegant" code that does something complex in line 3 lines, and you think "hmm, this is a puzzle, and I'm going to be staring at it for 20 minutes before I'm convinced that its 100% correct." We actively tell our engineers not to be clever. Write boring code that is obviously correct, and don't worry if your boring code is 25 lines when the elegant code is 8. It takes you longer to write the elegant code, and it takes the reviewer longer to read it, and often times (though not always ) it's also more difficult to test. I love Go because of how boring and consistent and easy to read it is. The language and the task of "programming" melt away and instead you get to focus on solving problems.
- VirusNewbie 5y agoStudy after study has shown people fail at repetitive tasks, it is likely you do a much poorer job reviewing that 500 lines of Go code than your javascript. Using generics isn't 'clever'. It's like saying a loop is clever. It's abstraction, the opposite of clever.
- VirusNewbie 5y agoProbably a bunch of that code was needless boilerplate you could have gotten away with not writing if you had abstractions such as parametric polymorphism.
- leshow 5y agoIt's not as if it's a niche problem requiring a niche solution though. The problem is "how do I write my own data structures" and to the best of my knowledge Go's answer is: copy-paste everything and edit for each concrete type, use code gen, or pay runtime cost for interfaces. All of those solutions seem more complex than just having a type parameter.
- jshen 5y agoThey seem more complex compared to a type parameter when you are only thinking about this narrow situation. However, generics are not limited to this narrow situation and will cause complexity far beyond what you are imagining. Having said that, I honestly don’t know if generics are a net positive or not. What I can say is that go is one of the few languages where I can jump into an arbitrary go code base and make sense of it relatively easily. Risking that is a scary proposition for me.
- Fire-Dragon-DoL 5y agoThis can be said for any programming language and any community: there will always be bad code written by someone. Generic data structures are provided in many programming languages and there are many people that are very experienced in writing some of these, so being able to reuse, it's precious. In general the lack of generic price surfaces when you write libraries, not applicative code. But libraries are a big portion of a codebase.
- jshen 5y agoI’ve been coding for decades. I’ve used all the fancy functional languages, written production code at scale with complex type systems, etc. my experience, they don’t add a lot of value compared to the costs. In my old age I’ve grown to prefer go for it’s simplicity. I hope we don’t lose it, and you all have the option of using the myriad languages that already do what you are looking for.
- Fire-Dragon-DoL 5y ago
- danellis 5y ago> Usually, if you are thinking about generics you are reaching for abstraction when you don't need to be. That's pretty laughable considering the language designers included type-parameterized collections in the language. Apparently they recognized the need for them; they just didn't think you were smart enough to make your own. After all, Go was explicitly designed for programmers who are, in the words of its creator, "not capable of understanding a brilliant language".
- pjmlp 5y agoI also wrote hundreds of stuff from 1986 up to 1994, my first experience with generics, on Turbo C++ for Windows 3.1. Doesn't mean many of us want to keep living on that world. I advise reading books like "From Mathematics to Generic Programming"
- silisili 5y agoYou don't write singly linked lists of arbitrary data :). In my 20+ years of development, I've definitely realized everyone's brains and approaches work differently.
- deanCommie 5y agoYou do if you want your language to have a reusable Linked List data structure so that everyone doesn't have to re-implement their own version of it for each content type.
- silisili 5y agoThere are languages that do this already though. Use Python. Reusable everything, just wait for exceptions. I've spent time in C, Python, Go, Js, and some lesser known languages. I was really big into Python. Go seemed restrictive at first, but was immensely more safe and predictable.
- SamReidHughes 5y agoLinked lists are the one data structure that you never end up wanting a generic version of. They aren't really used as containers. (Except badly.)
- puddingforears 5y agoThey’re the easiest stack structure to implement. All your operations are against the head of the list and you either have a thing, don’t have a thing, or add a thing. I’d like to be able to maintain a stack of things whose types I don’t have to manually reify and erase. That’s not a tall order, and it’s certainly not “complexity”. It’s markedly weird that I can’t have that same structure and associated operations be usable regardless of the thing I’m working with.
- SamReidHughes 5y agoIf you want a stack you'll just use a growable array (in Go, a slice). A linked list is suboptimal. Linked lists serve a real purpose in some situations where you really do want O(1) behavior. One example is when you are performing the operation while holding a mutex. But it's never the sort of thing where the right tool is a linked list generic container.
- tptacek 5y agoYou wouldn't. Everybody goes into Go thinking that's absurdly confining. Some significant subset of Go programmers learn that they instead find it liberating. Programming is programming; you have an overwhelming number of degrees of freedom no matter what language you work in. It sometimes turns out that taking some of those degrees out of the language makes it easier to focus them on your problem domain.
- silisili 5y agoI could not have said it better myself, despite trying. Thank you.
- systemvoltage 5y agoThis is one of the best definitions of 'minimalism' I've seen.
- reissbaker 5y agoWhile it's true that some find it liberating, a large number don't — personally, I've written a fair amount of production Go code and found it unnecessarily verbose and repetitive in ways that generics would've helped. I imagine some of this is based on problem domain; if you're writing a web application for example, maybe you don't really need generics much. After all, how often do you need a function that logs in a user to also log in... a book you're selling? Not very often. And any advanced data structures probably live in your database: how much do you really need a B-tree in a webapp when you've already got one in MySQL? That being said for a lot of other uses, you really do want high quality data structures beyond "array" and "dictionary."
- theshrike79 5y agoYou say "verbose and repetitive", I say "easy to read without any surprises". The verbose patterns (if err!= nil for example) make the code predictable to read, you notice the code smell of missing error handling really fast.
- coryrc 5y ago
- durbatuluk 5y agoYou can do something similar to container package which has a double impl.
- bouncycastle 5y agoSingly linked lists are something from CS1 where you learn about data structures. You rarely use them in practice. In most cases slices and maps do the job fine.
- dilyevsky 5y agoThey also have absolutely terrible performance due to poor cache locality and putting pressure on GC
- bouncycastle 5y agoSource?
- mseepgood 5y agoCS201
- bouncycastle 5y agoOk genius, explain how exactly what the OP meant?
- puddingforears 5y agoThey make a great stack, though. Cheap to use and easy to implement.
- snovv_crash 5y agoUse a deque at least and amortize the heap allocations...
- puddingforears 5y agoWith generics I could justify the extra engineering work to make such a deque!
- coryrc 5y agoNobody needs to do that, but it would be nice to have sorted collections without dynamic casting or rewriting half of leetcode in every project.