27 ms·
I've been writing a lot of Rust lately after writing Go for 7 years now (unrelated, but that is incredibly odd for me to write out. It still feels like that fun
by nemothekid 6y ago
I've been writing a lot of Rust lately after writing Go for 7 years now (unrelated, but that is incredibly odd for me to write out. It still feels like that funny new language that came out of Google). I've always said that generics is overhyped (in Go), but I find that I write a lot of generic stuff in Rust that is somewhat surprising. For example we have a JSON API that returns data in the format '{"ok": bool, "data":...}'. In Go I might do something with json.RawMessage and pay for decoding twice, or annotate every struct with Ok/Data. But in Rust I can just have a type ApiResponse<T>. Then I can have functions that operate just on ApiResponse, or ApiResponse<T=Users>. This problem is solvable in Go, but in a different way and with less guarantees. However that power comes at a mental cost, that creeps in C++ as well. I spent more time playing type system golf trying to come up with the optimal type for whatever usecase. In Go I might just "do the work", but in Rust I've turned 5 minute functions into 30 minute api design thought exercises. The jury is out if thats is a good thing or a bad thing.
That said, the only feature I'd steal from Rust is sum types and getting rid of null. `nil` interfaces are the only language feature to actually cost me money and Option<T> is just better in every aspect, and Result<T> is much better than err == nil. I'd be perfectly happy with compiler blessed Option and Result types even if the larger language didn't support generics.
- nine_k 6y agoThe cost you pay for appeasing the type system is the cost you're not paying writing more tests around corner cases ("this function never returns null"), debugging segfaults, null pointer exceptions, "attribute not found" errors, memory leaks (lifetimes help here), etc. The type system may not always help you get your code out the door faster, but when you finally ship it, you have much easier time running it.
- whatshisface 6y ago>The cost you pay for appeasing the type system is the cost you're not paying writing more tests around corner cases I have spent a lot of time in Rust getting carried away with type system stuff that is not required for the actual program I am writing. I realize this when I go over it a second time and reduce line counts drastically by replacing my gee-whiz generics with primitive types. This is balanced out by an equal number of times where I've reduced line counts drastically by using the advanced type stuff to reduce the repetition that comes along with using primitives to represent a type that has way more structure than the primitive.
- hinkley 6y agoA year from now, isn't it the 'reduced line count' that will have value to you, rather than the churn?
- WJW 6y agoSometimes. Often the reduced line counts contain way more complexity per line and understanding it is just as hard. There's something to be said for code churn, as it keeps it fresh in the mind of whomever is on the team right now as opposed to "a guy that left eight years ago wrote this".
- hinkley 6y agoAs simple as possible, but no simpler. I sometimes use the analogy of haiku versus short story. You can pack a lot of meaning into a haiku, but few will be able to unpack it in the manner intended. A short story can get you to the point without filling a whole book to do so. And a lot more people can write a reasonable short story.
- pragmatic 6y agoExactly, the maintenance tax, you have to load the crazy type into your head and once you get to 2 or 3 layers of generics is just painful. C# and typescript both have this. The question is, what is beyond generics? We need a humane alternative that still provides the type safe guard rails.
- deleted 6y ago[deleted]
- chewbacha 6y ago> I realize this when I go over it a second time and reduce line counts drastically by replacing my gee-whiz generics with primitive types. I do this too, but I’ve also come to realize that fresh perspectives and newly learned patterns may be more of the reason than being a little over zealous. Edit: forgot to mention that this happens to me in most languages, not just rust.
- 6y ago
- Thaxll 6y agoThat's up to debate, you have to prove that in x.y.z language the time spend for maintenance would have been avoided if x.y.z had that feature from the start. Especially language like Rust that have a big learning curve / blockers, is it justified on the end? I'm not sure. In Go I never felt that omg it misses some big features we're screwed, we're going to pay the cost of running that in Prod. All the services I worked on while not being perfect ran like a clock without issues on the long term, and it has to do with Go "simplicity", eventhough you never wrote the code you can actually jump into any code base without issues, there is no weird abstraction layer / complexity that takes you day to understand. For me the fact that Go is a "simple" language is very powerful because on the long run it's much easier to maintain.
- throwaway894345 6y agoMoreover, not all domains require you to catch every error. In many applications, it's just fine to ship a few bugs and it's much better to ship a few bugs here and there rather than slow down dramatically to appease a pedantic type checker. This is especially true when bugs can be found and fixed in a matter of minutes or hours and when the bugs are superficial. And I also contend that the more pedantic the type checker, the more likely that the additional bugs that it finds are of diminishing importance--they are less and less likely to be a downtime issue, they are increasingly likely to be in very rarely hit paths. I like Rust a lot and I hope to get to use it more, but "added type safety at the expense of iteration velocity" is not a good tradeoff for my domain and I suspect many others (although its iteration velocity is improving monotonically!).
- nine_k 6y ago(1) This is why you can even ship code written in JS or Python. (2) This is why Typescript and mypy exist.
- throwaway894345 6y agoI agree, although my experience with Mypy has been miserable. I’m not sure the costs are less than the gains. Also there are other tradeoffs, like performance and artifact size (numpy and pandas alone are 100mb).
- atdt 6y ago[[citation needed]]. "Everyone knows" that type systems reduce bugs, but actual evidence for that is pretty weak. https://danluu.com/empirical-pl/ https://danluu.com/empirical-pl/
- sethammons 6y agoThat study calls out significant issues. I can go from personal experience. Porting python to Go. In python, we had to have tests dedicated to ensuring the right types were handled the right way. Is it a string or an array passed in? Welp, need a new test to cover that. Whole classes of tests go away with more advanced type systems. Those tests were needed to prevent those classes of bugs. So better type system == removing of whole class of bugs.
- sixstringtheory 6y agoCame here to say I've had this exact same debate. We were writing long Python test suites to check types. I constantly (and playfully, I don't care to die on this hill) pointed out this is fully automatable with a static typing system. I remember many times being told to just read thousands of lines of uncommented tests in order to understand some thing I was trying to debug. (Don't get me started on Python stack traces!)
- viraptor 6y agoI've started applying `mypy --strict` to my new python code. It caught so many issues already it's definitely worth it. Mostly in cases of uncommon error handling, some in code which was tested but under wrong assumptions and would actually fail on production. (This is a problem with "you can test types approach")
- SnowflakeOnIce 6y agoYes, mypy is terrific, and has changed the way I write Python programs. Taking this gradual typing tool a step further, you can run your tests with the typeguard plugin for pytest, which will dynamically check the types of most values, pointing out places where your types are a lie. https://typeguard.readthedocs.io/en/latest/userguide.html#using-the-pytest-plugin https://typeguard.readthedocs.io/en/latest/userguide.html#us...
- gorgoiler 6y agoIn my experience I find it very common to write, rewrite and rerewrite code a lot when embarking on a new project. For various reasons, I embark on more new projects than I work on long term ones, which I think is a factor here. It takes a while for something to settle down enough to say this version is going to be the code for the long run. At that point, solidity in testing and gradual typing can be added, usually starting with the public interface. Languages where I’ve had to satisfy all type errors in the various fragments of half brained code I’ve written for version 0.0.85 have always felt a little cumbersome. The compiler’s type checker is a perfectionist looking over my shoulder. (Go is one of those languages. Ruby is not.)
- trixie_ 6y agoI'm the opposite. New applications are the ones you refactor the most, and refactoring is an order of magnitude easier/faster when the code is statically typed. Refactoring any dynamically typed application (regardless of size) is a manual operation, and error prone. But then again I rarely deal with type errors, when I do it's the compiler looking out for my often 'application ending' mistakes.
- randomdude402 6y agoAs a person who chooses Python whenever it seems reasonable, I agree. Go, the language, is simple. Hard to argue with, and sounds great. The code I have to write though, it's quite simpler to do it in Python more often than not.
- entha_saava 6y agoThis is a generalized feeling about good static type systems. What is missing is a language with good static type system (Algebraic data types, stream/iterators, generics), simple and having GC, for application domains where prototyping speed matters.
- neilparikh 6y agoI think Swift satisfies all of those those criteria, and doesn't have a steep learning curve since you can write in an imperative style if you want. F#, OCaml and Haskell (and other ML-family languages) satisfy the first 3 criteria (type system, simple and GC) and depending on your familiarity with the language, can be fairly suitable for fast prototyping. For example, I write most of my new personal projects in Haskell, and I'm able to iterate pretty rapidly once I have a skeleton of the system in place (with liberal use of typed holes to ignore things I don't care about implementing right now). For some projects, I find I'm actually able to prototype more rapidly than I would be able to in an untyped language, because the language helps me express the shape of the data through algebraic data types, and then the functions end up having "one obvious implementation" that follows the structure of the data.
- entha_saava 6y agoReference counting still requires you to keep track of cycles. Also performance is less than GC, especially in multithreaded environments. And Swift is not a serious language outside apple ecosystem. OCaml is actually very good language. I hate how people outright dismiss it mentioning multicore. Neither JS nor Python have great multicore story. And most applications don't need multicore. Wish there was a good static compilation toolchain for .net core. F# would gain much more traction then.
- azernik 6y agoBoth Javascript and Python are perfect for this, IMO - both languages have syntax for type annotations which are ignored by the intepreter, but are respected by external typecheckers. Mypy for Python (https://mypy.readthedocs.io/en/stable/ https://mypy.readthedocs.io/en/stable/) and Flow for Javascript (https://flow.org/en/docs/ https://flow.org/en/docs/) are my personal favorites, and have all the features you describe. And importantly, both languages have very strong library support.
- cageface 6y agoTypes also are also massively useful in making better tooling. The ability to refactor with confidence and get meaningful autocompletes is already enough justification for a static typesystem.
- mrmonkeyman 6y agoSame here. Go tends to make me "just do it". I personally think it's a big win, because I believe systems need to be composed and the components they are composed of as simple as possible. As a human though I tend to waste time coming up with fancy abstractions. Generics are exactly that. Fancy, nice to have, but I completely fail to see how they are necessary.
- platinumrad 6y agoI mostly disagree with this post, but vouched for it because there is absolutely no reason for it to be dead.
- totalperspectiv 6y agoIs there an old quote about `as simple as possible but no simpler`? Go rides the simple line really well occasionally, but generics is an area where it falls into the 'simpler' category.
- entha_saava 6y agoMaybe you think go is simple. But I don't. You need a for loop for what is done in other languages with one method call. Removing an element from an array doesn't look like that. It is some slice appending trickery. Having null and having to check errors every 5th line or so.. It lacks idioms like list comprehensions or map / filter. Reading code is spent in details like whether a for loop is index(), count(), map() or filter(). Instead of some simple code like x = condition ? a : b you are writing imperative verbose code like: if condition { x = a } else { x = b } Go maybe simpler than enterprise-style java. But that's not 'simple'. http://archive.is/YPxJP http://archive.is/YPxJP
- dom96 6y agoI like to think that how much time a language makes you spend designing the API is a spectrum, and Rust in particular is very much towards the extreme. There are a lot of languages out there with generics that do not place the cognitive load that Rust's borrow checker puts on you. I suggest you give those languages a try if you feel that 30 minutes is too long. I must say I am biased, since I develop a language that I believe fits the sweet spot here. I would encourage you to give it a try: https://nim-lang.org https://nim-lang.org
- pasabagi 6y agoI don't consider myself a particularly good programmer, and I don't find the burrow checker is a substantial source of cognitive load. I think I get way more friction from: - library authors that go crazy with generics. - the million ways rust makes performance tradeoffs explicit (even when you're writing part of the program where performance simply doesn't matter). - the million-and-one things you can do with an option type. - the arcane macro syntax. I could probably go on. I've been writing a lot of rust because I wanted a low-ish level language with good C interop, and I didn't want to learn C++, so I wasn't at any point a rust fanboy. I very much appreciate not having to be a genius to avoid segmentation faults, but other than that, I think rust is a somewhat ugly language - for the simple reason that it has a lot of features, some of which partially overlap, and most of which are vaguely inconsistent. I'm probably sounding a bit harsher than I mean to - obviously, you can't expect a language like rust to have the simplicity and consistency of something like lua, and by and large, it's better than anything else I write programs in. Still, the point is, as somebody with a lot of (fair and unfair) complaints, the burrow checker is not one of them. It complains rarely, and when it does you're almost always doing something stupid, unless you're doing something fairly arcane, in which case, you should probably use unsafe.
- bcrosby95 6y agoThen you're a good programmer. Rust effectively forces you to code like you're writing a multi-threaded app even when you aren't. There's a reason why people suck at writing multi-threaded apps: because it's hard. This is what people are fighting when they fight the borrow checker. And this is why so many people find it frustrating. There's all sorts of designs that flat out don't work or are way more effort than they're worth.
- aplummer 6y agoI can dramatically shorten development time with generics + codable in Swift using a similar approach - to the same code in objective C it’s like night and day
- mov_ 6y agoI can relate, maybe this is the paradox of choice? That said I agree completely, `Option`/`Result` themselves (even if they are just intrinsic language elements, not user-implementable types) are valuable.
- vlunkr 6y agoDo we have a name yet for the internet phenomenon where every time Go is discussed, Rust must be immediately brought into the conversation, and vice versa?
- asjw 6y agoI think the word you're looking for is marketing
- jeffrallen 6y ago"oxidation"
- munificent 6y agoIt shouldn't be that surprising. Both are "low-level" languages that came onto the scene around the same time, are highly opinionated, but stake out very different points on the design space. If you start talking about changing the recipe for Coca-Cola, surely Pepsi is going to enter the discussion at some point, right?
- gver10 6y agoThis doesn't explain the obsession with Rust. Fitting analogy: If there's an article about McDonald's, people would always talk about Wendy's instead. No one would mention BurgerKing (C++), Subway (D), KFC, ...
- viraptor 6y agoI see zig and d mentioned a lot on the rust/go posts about features and C++ on the posts about performance. It doesn't seem to be go/rust specific.
- darksaints 6y agoEverybody that talks about rust is talking from a different perspective with different values. What makes rust different from other languages is the breadth of use cases for which rust is a candidate worth mentioning. That's not so much an obsession as it is an availability bias on your part. You're seeing different people talk about rust obsessively in different contexts and assuming that those same people talk about rust in all contexts. If any of these features is of significant value to a programming use case, it is worth talking about rust: * Speed * Type safety * Memory safety * Memory determinism * Latency * RAII-based resource acquisition and destruction * Concurrency correctness / safety * Minimal runtime requirements * Low level bit manipulation (eg. Cryptography, compression) * Startup time * Networking This isn't exhaustive, but it gives a lot of different people in different domains working on different problems a reason to talk about the same language when comparing to their usual choices.
- gowld 6y agoGo has had generics for years. But they are in a preprocessor not main compilation.
- jasonhansel 6y agoIndeed. If Go had a built-in macro preprocessor, generics would be less necessary, but macro programming has plenty of problems of its own...
- bradstewart 6y ago> I spent more time playing type system golf trying to come up with the optimal type > The jury is out if thats is a good thing or a bad thing Well said. I have this same thought with TypeScript on a frequent basis.
- cambalache 6y agoI am just learning the ropes of Typescript with React and Christ sometimes it is hard not to think it is a veritable clusterfuck.
- vlads_ 6y agoFun fact: because json is a reflective package in Go, solving your problem is quite trivial: https://play.golang.org/p/-TZ5b9Su1or https://play.golang.org/p/-TZ5b9Su1or . As for programming with types, that's partly what Go was trying to avoid: https://news.ycombinator.com/item?id=6821389 https://news.ycombinator.com/item?id=6821389 . And I agree with Pike on this one. The nice thing about Go for me is that I'm just writing code. Not defining a type hierarchy, not rewriting some things to get them just right, not defining getters, setters, move and copy constructors for every type :). Just telling the computer what to do and in what order. When I'm writing a library I'm defining an API, but that's about it; and you can usually steal whatever the standard library's patterns are there. I disagree about nil as well; I think Go's zero value approach is useful, and basically impossible without nil (it wasn't necessary in my code, but I may want to instantiate an ApiResponse object without a data structure ready to be passed in). A little bit of a rambly response from me, but, all in all, I think I'll be one of the stubborn ones which refuses to use generics in his code for a long time.
- nemothekid 6y ago>I disagree about nil as well; I think Go's zero value approach is useful, and basically impossible without nil (it wasn't necessary in my code, but I may want to instantiate an ApiResponse object without a data structure ready to be passed in). I like your solution to my imaginary problem, but I am going to counter this one. Now I'm salty because nil interface[1] actually bit me once and cost me. Go's zero value approach also exists in Rust, but is type safe. Basically every primitive type, and Option<T> have zero values. Any struct that is made up of those values can also safely have zero values. Then for those that don't, you can implement your own zero values. This is called Default in Rust. Go's zero value approach is perfectly possible, and arguable better without nil. And even then, the number of times I've seen a service crash because someone "forgot" to initialize a nullable type, and passed it to a function that then exploded isn't an issue I should deal with in 2020. [1] https://medium.com/@glucn/golang-an-interface-holding-a-nil-value-is-not-nil-bb151f472cc7 https://medium.com/@glucn/golang-an-interface-holding-a-nil-...
- steveklabnik 6y ago
- shpongled 6y agoFunny, I also have an `ApiResponse<T>` in my backend Rust code that serves exactly the same purpose (same name even) !
- d0m 6y agoFrom someone who hasn't learned/considered Go for any real project so far, would there be any benefits in going Go instead of Rust? Or learning Go instead of Rust? The way I look at it, and I could totally be wrong, is if you go for a different language for your back-end than your front-end, it betters pay off big time. I find Go and Typescript to be in a very similar ballpark in term of productivity, but with Typescript having a huge advantage since you can reuse all the learning/tooling from the front-end. Rust on the other hand really adds something to the table with the memory safety and zero-cost abstraction. TL&DR: It feels like either you eat the bullet and go Rust for memory safety, or Typescript is a better choice. Of course I'm overly simplifying. Thoughts?
- chrisweekly 6y agodecent points, I like TS too -- but commenting to help w the idiom: it's "bite the bullet" (ie, accept the pain and deiberately suffer through it now), not "eat the bullet" (commit suicide).
- d0m 6y agoThanks, english isn't my native language so I appreciate the help
- estebarb 6y agoLanguages are tools, so it depends on your problem. Go shines when you have a lot of parallelism, and not a lot of concurrency (although sync package is fantastic). Web servers, data processing pipes, task queue consumers... Also the language is simpler. Personally I think in it like C vs C++ or RISC vs CISC. And last, but not least: Go have faster compilation times. Rust compilation is slow, and for some tasks that requires retrying (like learning a new language) compiling fast is very valuable.
- jfkebwjsbx 6y agoIt depends on what you want to do. It is not about picking one or another. For the majority of software (I guess you are referring to web apps), simpler/GC/scripting languages like TypeScript or Go are better. But, if you really need something low-level, then you need C, C++, Rust, Zig, etc. and there is no way around it.
- nurettin 6y agoSubstituting null with optional helps with getting a stack trace of what's going on. However, it doesn't get rid of programming errors. What does get rid of errors is IDE support for nullable types which warns the programmer that they have accessed a property without checking for nulls. Take kotlin and Intellij/IDEA for instance.
- nemothekid 6y agoAn optional is the compiler telling me to check for nulls. My program won't compile if I don't check for nulls. IDE support is half baked, someone can always turn it off.
- nurettin 6y agoThis doesn't sound right. Could you paste an example of a misuse of optional (for example: an unchecked unwrap) causing a compilation failure instead of a panic?
- jpttsn 6y agoIn Swift `let x = things.first` won't compile but `let x = things.first ?? "empty"` and `let x = things.first!` will. Does that count? (Probably mangled the Swift, doing this from memory)
- nurettin 6y agoMy swift isn't good, but since you didn't specify a type for x, I think it should compile anyway. But if things is an empty array of T, first may return nil and x will be of type T?. If things is an array of optional, x will be of type T??
- kelnos 6y ago> I spent more time playing type system golf trying to come up with the optimal type for whatever usecase. In Go I might just "do the work", but in Rust I've turned 5 minute functions into 30 minute api design thought exercises. The jury is out if thats is a good thing or a bad thing. The way I tend to look at this is the 30 minutes I spend up front making my types work will usually save me hours of time later (sometimes much later, and spread over different coding sessions), because if I'm using the type system to enforce constraints, I'm not going to have to worry about writing buggy constraint code. When I was learning Scala (after working in Java most of the time), I noticed that I would sometimes spend quite a bit of time getting short snippets of code correct so the types would line up. The result would be shorter than the equivalent Java code. But I had much more confidence in that code actually working, without needing to write tests (or at least as many tests), because I was leaning hard on the type system to prove the code correct. You can do that to some extent in Java, but the type system there is a bit weaker, and the standard library and common idioms make it harder to do. Ultimately if I have a chunk of Java code and a chunk of Scala code that does the same thing, I'm much more confident in the Scala code because I know scalac is providing me stronger guarantees than javac, assuming I've written the code to make good use of the compiler's abilities.
- y7 6y agoI've also done this. Maybe a good rule would be to just write the function for the single type you need it for, and only introduce a generic type parameter when the need for it arises?
- imron 6y ago> The jury is out if thats is a good thing or a bad thing. My vote goes towards good thing. One of the things I like most about Rust is that it forces you to think through your design and address complex tradeoffs, and often won't even compile until you do. What it costs you in development time, you'll make back in reduced maintenance. The former is a visible cost therefore you feel it more than the latter which is invisible when things run well. This is why Rust can feel less productive even if it makes you more productive in the long term if you take in to account less maintenance.
- gfxgirl 6y agoright tool for the right job. I wouldn't want to spend that time one a one off script I only expect to run a few times. I also wouldn't want to spend that time only to find that my assumptions were wrong or the requirements changed and I have to throw it all away for a new class puzzle.
- dpc_pw 6y ago> I wouldn't want to spend that time one a one off script I only expect to run a few times. You don't have to. No generics, `.clone()` and `.unwrap()` everywhere, and the Rust code goes brrrrr. :D
- kortex 6y agoOr just...not deal with any of that, and literally bash my way through it. I hated the bash learning curve because it's so zany compared to "sane" langs, but once you hit a point in comfort, it's "muck around with syntax for a few minutes, applying to a test case of a few examples, dial it in, and let it rip on a few GBs of data and go work on other things". stringly typed pipes go brrrr XD. Composing unix utilities is horrific and beautiful all at once. Shellcheck helps a ton. Recently started getting into Xonsh cause it still makes piping programs super easy, while being still fairly easy to provision. Really wish there were a (stable) go-based scripting language and shell. There's tengo and some other things, but not primetime ready.
- majormajor 6y ago> I spent more time playing type system golf trying to come up with the optimal type for whatever usecase. In Go I might just "do the work", but in Rust I've turned 5 minute functions into 30 minute api design thought exercises. The jury is out if thats is a good thing or a bad thing. I usually do stuff like this as a YAGNI exercise. Don't spend the extra 25 minutes thinking about it until you know you have 3 or so cases where you'd actually be sharing code. But at that point... the consistency you can get starts to become attractive, if you want the behavior to stay consistent in the future!
- dathinab 6y agoOne think I realized is that properly using the type system is a skill you have to/should learn. It includes: - Having some understanding of how type systems tend to work and common patterns around them, preferable in a abstrac non language specific way. Do not confuse it with knowing formal CS since type theories, it's not the same. - Knowing how to effectively use the type system to encode important variants. But probably even more important: - Not getting obsessed with trying "perfectly"/"optimally" use the type system. - Knowing that the moment your types and their relations get too complex it might not be worth it at all, even if you encode use-full variants. Sometimes just having runtime checks is so much better from a API UX point of view. Getting complex type system based API's right is hard and from what I see in the open source community most people do not have the skill to do it right. (Through this doesn't mean not using the type system to encoded constraints, just not over using it!). A common case where this happens is when people try to use the type system to force a DSL into a language which isn't very compatible with that kind of DSL. While I often see people learning about how they can use advanced features of a type system but they do not learn when to _not_ use it. Disclaimer: I just realized that what I see as Simple usage of the type system the parent post might already see as advanced usage.
- pwm 6y agoThis is spot on.
- dmix 6y ago> but in Rust I've turned 5 minute functions into 30 minute api design thought exercises. This is very real. One reason I like Rust for serious projects that deserve this level of thinking time, but I'm wary to use it for simple 'toys'. Go was far easier to jump into but also far easier to push against its limits. Some sort of compromise might seem better here but I like using the best language for the job. Rather than some all-encompassing developer experience or language use-cases.
- onebot 6y agoExact same boat as you. Been doing Rust for 2 years now and it is so true about the time spent thinking about how to be "more Rust-like". I think you summarize it perfectly though, my favorite parts of Rust are Option/Result.
- Cthulhu_ 6y agoI think (disclaimer: not a language expert, don't know Rust, etc) that it's a tradeoff between verbose and repeated but readable and simple code, vs generic reusable but more difficult code. In Go you can take most code at face value, with generics you have to keep use cases and possible types into consideration.