5 ms·
Your claim that F# or even C# are as concise as a dynamically typed language is the crux of your argument, and is the weakest part of your post. I haven't work
by wcarss 16y ago
Your claim that F# or even C# are as concise as a dynamically typed language is the crux of your argument, and is the weakest part of your post.
I haven't worked with F#, but I have read a share of C# code. A non-trivial program is likely to need some methods to respond to many types; in this circumstance C# lets you write many methods, use generics, or (now I believe) use dynamically typed variables. Writing many methods is hard to maintain, and not at all concise. Using generics is theoretically great, but the syntax in C++/C# is just awkward and writing type-agnostic code with generics is nigh unreadable.
In Ruby or Python you have duck-typing, and you can easily be type-agnostic and concise; in fact if you are writing code in one of these languages, you /should/ be both of these things.
Duck typing is fantastic for true object orientation: "If it walks like and duck and it quacks like a duck, we can safely treat it like a duck." This reliance upon support for response to messages instead of reliance upon types is often the key to being concise and readable.
In ruby, for example, I can use object.responds_to?(:method_name) and be assured that the object will support this piece of the interface before I attempt use. This is an elegant solution to keeping code type-agnostic, and it emphasizes the best sort of object oriented methodology.
This is why I love Ruby.
- DougBTX 16y ago> in this circumstance C# lets you write many methods, use generics, or (now I believe) use dynamically typed variables. Or you could be explicit about the interface you are writing the duck-typed code against. The problem here is that you can't assign an interface to an existing type, and adding interface declarations results in more code. It will be interesting to see whether this functionality (extension interfaces and inferred interfaces) makes it into C# in the next 5 years. My guess is that it's functionality which is possible to add, but we're not there yet.
- Rusky 16y agoobject.responds_to?(:method_name) is just a run-time variation on generics constraints. C# could use a bit more work on its syntax there, but something like go's inline interface definitions would make it just as nice as Ruby.
- wcarss 16y agoThis is entirely fair -- my intended point is that C# is /not/ yet concise for operations that are sugar-sweet in Ruby, and that's why I don't love to use it.
- jganetsk 16y agoBut statically typed languages have duck typing too. Except it's called type inference. And F# has it.
- therockhead 16y agoI dont believe Duck typing and type inference are really the same thing.For duck typing the type is unimportant, it only cares about the operation, types matter for type inference. The behavior of structural typing in languages such as Scala are is closer to Duck typing IMHO.
- wcarss 16y agoThis is patently false. Duck typing: http://en.wikipedia.org/wiki/Duck_typing http://en.wikipedia.org/wiki/Duck_typing Type inference: http://en.wikipedia.org/wiki/Type_inference http://en.wikipedia.org/wiki/Type_inference Type inference relies upon known, preset interfaces and inheritance from other types. Duck typing relies solely upon the methods being used. In duck typing, this means that the user finds out at the time of use whether or not a method is supported by an object. Here, the "interface" to a type is not set in stone. It is inherently dynamic and as long as the message you pass is supported, (duck->quack), there isn't a problem. The mental jump which many people fail to make is to understand that Object Orientation is about message passing, not types. The key questions are, "what message are you sending", and "does the receiver have a response" - it got dogmatized somewhere in small-memory static-land long ago that the best or perhaps only way to tell if an object will respond is through static definitions of complete interfaces, which came to be very strongly associated with our conception of a "type". Once the compiler has used it to check interface constraints are unbroken, this information becomes useless and unchangeable. Ruby is an example of a language that does not use that means of answering the questions. Instead, an object has dynamic metadata about what messages it supports (specifically a hash of the method names), and uses that (malleable) data to generate an answer. It is fundamentally different than type inference in a statically typed language.
- prodigal_erik 16y agoDuck typing is a problem when it's done by message name and those names aren't distinguished by namespaces. We're already starting to hear horror stories of Ruby libraries that want the same name to mean different things, especially with monkey-patching.
- statictype 16y agoI believe the Go language gets most of the effects of ducktyping in a statically typed language. The compiler is smart enough to figure out if an object adheres to a specific interface without having to explicitly tag that object as implementing the said interface. So this basically means if you have a method which just calls 'read' on it's argument, you can define a 'read' interface and it will accept any existing type that responds to 'read'
- steveklabnik 16y agoHow is a compiler supposed to figure out if I've added a method at run time?
- statictype 16y agohm... I think I didn't explain properly (or I misunderstood your point). Lets say you have a method the sole task of which is to call call .read() on its argument and return a single char. char readch(obj) { return obj.read(); } Now, since I have not declared any explicit type for obj, the compiler would generate code like this: interface readch_obj { char read(); } char readch(readch_obj obj) { return obj.read(); } So the function basically takes in an interface readch_obj which defines a single read() method that returns a char. Now, the trick is, the compiler can intelligently recognize that the FILE object has a method with the required signature (char read() ) and that the STRINGIO object also has a method with that required signature and so the compiler automatically tags the FILE object and STRINGIO object as implementing obj_readch and so, either of those objects can be passed in as an argument to readch(). Note: I'm not saying this is how the Go compiler actually works but this is the basic concept from what I understood. The language doesn't need to allow for adding methods at runtime for this to work. If the language did have the scaffolding needed to add methods at runtime, then yes, this technique wouldn't work and thats probably the fundamental difference between ducktyping and this (structural subtyping? not sure what it's called).
- steveklabnik 16y agoSorry, it's that I was reading on my phone and missed your 'most.' Go's structural typing stuff seems pretty cool, but what I was trying to point out was that it can only get most of the way there, not the whole way. In Ruby, for example, I can define singleton methods, and method names based on a dynamically generated string. I'm not sure how a compiler would be able to do stuff like this. At least, not easily. Then again, I haven't been keeping up with the more recent advances in compiler stuff, so maybe someone has already done this.