3 ms·
I've worked primarily in Java and C++ for the past few years, but also with several dynamic languages. I sometimes miss the expressiveness of Python, but I can'
by oxymoron 10y ago
I've worked primarily in Java and C++ for the past few years, but also with several dynamic languages. I sometimes miss the expressiveness of Python, but I can't say I'm ever frustrated by a strong type system nor does the compile step annoy me as long as my write-compile-test cycle is reasonably quick (usually achievable). With Java 8, and even more so with Rust, I'm less frustrated by the lack of expressiveness, so I find myself missing dynamic languages even less.
- flukus 10y ago> but I can't say I'm ever frustrated by a strong type system Never? I can't say it happens very often but occasionally the type system get's in the way, usually when you want the function to be type T1 but sometimes it'd be convenient to do a little bit more if the type is also T2.
- smaddox 10y agoRust supports algebraic types and switching over the type, which handles your example quite efficiently. You would simply define an algebraic union of T1 and T2, and switch on the type into the desired code for each branch.
- flukus 10y agoWhat does that look like in code? I was using c# so I did the dirty: T1 arg; var foo = arg as T2; if (foo != null) .... Also, how do we format code here?
- shakna 10y agoI expect Rust should be able to handle this nicely, but I'm more familiar with Pony... So here's how to do it nicely in it: fun f(x: (T1 | T2 | None)): ReturnType => match x | T2 => /* do something */ | T1 => /* do something else */ | None => /* Handle badly behaved. Optional to have, compiler can enforce good behaviour if you want. */ Note: You can see formatting at https://news.ycombinator.com/formatdoc https://news.ycombinator.com/formatdoc
- iopq 10y agoIn Rust, you'd define an `enum` of two types. enum Either { Type1(T1), Type2(T2), } let's say you get a value of type Either then you can match on them: match value { Type1(v) => func(v), Type2(v) => func2(v), }
- flukus 10y agoDoes that let you work with the default type? What I was doing in c#: function(T1 thing) { //do normal T1 stuff here var foo = arg as T2; if (foo != null) foo.T2Stuff(); //more normal T1 stuff } If I'm understanding your example I would have to wrap all the T1 stuff in a match.
- mathw 10y agoYes, you do. There is no idea of a 'default' type here, because each variant of the enum is treated exactly the same. Your C# example assumes an inheritance relationship between T1 and T2 (i.e. T2 inherits from T1, so you can pass it to something expecting a T1 reference). Rust doesn't have type inheritance, so the only way you can define relationships between types is to have something external tell you how to package them together, which is what the enum would do here. So it's not a parent-child relationship between the types, it's a new thing which says "here is a thing which can be a T1 or a T2 but not both at once". Not having OO does require you to think somewhat differently about how to build your data structures in Rust. I've found my intuition from Haskell is a stronger guide when working with Rust, but since Rust's type system is much more like that in an ML-family language this makes quite a bit of sense! Sadly this does increase the learning curve for more mainstream languages. (Rust does have trait inheritance, but all that says is that to implement trait T2 you have to also implement trait T1, and thus anything working with a T2 can assume that thing is also a T1).
- flukus 10y agoThanks. The above example was actually using two entirely different interfaces. It seems like rust is quite similar to the OO subset I prefer to use. In this particular case it would have been a better match because traits can implement methods. Rust is on my "to learn" list over the holidays.