I haven't listened to this episode yet, but... thank you for a most informative post! I was ignorantly classing languages in only 2 of those dimensions up until now. :)
On Nov 5, 9:19 am, Reinier Zwitserloot <[email protected]> wrote: > I wish I was there, because the vast majority of points raised have > absolutely zip squat to do with dynamic vs. static. > > 1. Growing existing types - can be done globally (so called dynamic > scoped), which is awful, because once your project grows beyond the > small, everyone overriding everything just makes it impossible to > figure out what is what, and you get conflicts. This is what rails > does - it redefines half the ruby core. An alternative is lexically > scoped extensions, which is really much nicer; an import statement > adds methods to, say, all strings, but *ONLY* inside the file that > contains the import statement. Both C# and Scala (both very much > statically typed languages!) can do this. Clearly, no relation > whatsoever to dynamic v. static typing. > > 2. Growing interfaces - nobody can do that without stuff breaking. If > you need to support pre-extension stuff while still extending, with > default behaviour, then you can do that. Scala can do this (traits), > and scala is statically typed. Clearly has not one iota to do with > dynamic v. static. For those who don't know scala: Imagine you could > give interface methods a method body, which will be used for all > classes that implement your interface but do not specify an > implementation. This method body can't use any of the fields of the > class, of course, so it's not as unique as being a superclass. Voila: > Extensible interfaces, in a fully static language. > > 3. duck typing the way it was explained in the roundup - in other > words, ad hoc interfaces, in other words: Give me any object that has > a 'doFoo();' method. Again, has nothing to do with typing systems. In > scala, you can make structural types which do exactly this: You can > create a type that says: Anything that has a doFoo() method. If you > then accept this type as, say, a method parameter, you can call doFoo > () on this parameter, and any object of a type that includes a doFoo() > method can be passed in. > > 4. Static typing is verbose. No, it isn't. This has nothing to do with > static typing. > > Time for a rehash of the 4 dimensions of type systems. > > Weak vs. Strong: This refers to whether or not the *OBJECT* knows its > own type. C and C++ are *WEAK* even though they are also static. You > can cast, say, a String to an Integer object, then get core dumps as > the methods that work on Integers work on String's data structure > which is nothing like Integers. Python, Ruby, Javascript, Java, C#, > and Scala are all Strong. Basically, if objects have a .getClass() > kind of method, you're looking at strong typing. Strong typing also > implies you get cast errors of a sort. So, in python, when you call a > non-existent method on an object, you don't get a core dump, or > unspecified behaviour. you get clear behaviour: A method missing > error. > > Static vs. Dynamic: Whether *REFERENCES* have a type. So, in: "Object > x = "foo";", x is a reference, and its type is "Object". x, being a > reference, points at something. It points, in fact, at a string, which > has a String type. The fact that "foo" knows its a String means java > is strongly typed. The fact that 'x' also has a type, means java is > statically typed. In e.g. javascript, which is dynamically typed, you > just write "var x = 'foo';" and as a result 'x' itself has no type, > but the thing x is pointing at, does. *THIS*, and only this, is static > vs. dynamic typing. You can of course mix the two, which is just what > groovy and C# do, even though most people refer to these as 'static' > languages. They are actually hybrids. Java is very much static. > Sometimes, latent typing (where the compiler INFERS the type of a > reference, instead of just not caring about what it is) is confused > for dynamic typing. Don't do that. > > Nominal vs. Structural: A type is simply an assertion about an > object's nature. Thus, this: [Anything with a getFoo() method], > qualifies as a type, technically. There are two ways to think about > types: You can think about what a type says about structure, or you > can think of types by themselves, generally identified by an > identifier (e.g. a name). This is nominal vs. structural typing. Java > is 99% nominally typed; if I have: class Foo { void shoot(); }, as > well as interfaces Gun and Camera, also both with shoot() methods, > then a Gun isn't a Camera, and a Foo is neither a Gun nor a Camera. > They ALL have the exact same structure (namely: I have a shoot() > method), and yet they aren't the same type, because they don't have > the same name: Thus, nominal typing. Java is structural in how it > handles main methods - a runnable class is one that has a static void > main(String[] args) method, regardless of its nominal types (the > interfaces and superclass). Scala is a hybrid; you can pick and mix. > Most dynamic languages are structural. Just interact with structure > (call methods, read or write fields), and if the object has that > structure, it works, and if not, it doesn't. An obvious downside to > structural typing is that you can shoot yourself in the foot due to > lack of namespacing - namespacing every method is rather tedious, so > you don't do it, and then you get to call shoot() on a Gun, thinking > it was a Camera. > > You can mix structural and static if you want: In such a language, you > would be able to cast a Camera to a Gun without any issues, because > they have the same structure. If you want to create a method that > takes 'any object with a foo()' method, you just create an interface > with a foo() method, make it private if you want, even, use that as > method parameter type, and it'll work. This isn't how java works, of > course, because java is nominally typed. BGGA's (the closure proposal) > biggest downside is that it turns java into a structural/nominal > hybrid, as it introduces stuff like {String, String => Integer} as a > type, which is obviously structural. > > Latent vs. Manifest: When you write: List<String> x = Arrays.of("a", > "b"); - you don't actually specify that Arrays.of() is going to build > a list of strings. It's not inferred from the left, it's inferred from > its arguments (which are both strings). Yet, it is very much static > typing: That is functionally equivalent to Arrays.<String>of("a", > "b");, but it's just that the compiler inferred the <String> part of > that. Contrast this to dynamic languages, where "String" (or List) > isn't needed. Java infers very little, but scala infers more, and > haskell infers a lot more. Inferring types means you have a latent > language, and if the language mostly forces you to be explicit, you > have a manifest language. Virtually all languages are hybrids, and > this term doesn't really apply to non-static languages. Boo is almost > exactly like python, but statically typed. It's very latent, so almost > all python code just runs as boo, and yet one is static, and the other > is dynamic. A lot of the 'it's all so verbose' complaints actually are > complaining about java's manifest tendencies. Has nothing to do with > static v. dynamic. > > Example: > > You could easily add the following rule to java, so that the following > is legal, and figures out that you must have meant that the method is > to return Numbers: > > def foo() { > if (something) return 1; > else return 2.0; > > } > > because the most specific commonality between 1 and 2.0 is > java.lang.Number. This isn't legal java, but it could be. That would > be an example of latent typing - no need to specify types, the > compiler infers them. > > Only after you understand all these distinctions, you can make > reasonable arguments about pros and cons, without the discussion being > all over the place, drawing all sorts of faulty conclusions, like the > roundup. For example, you can weigh the benefits of shorter code > (which isn't so much about not typing much, but more about reading > less, which can help), against the obvious conclusion that with a lot > of latent typing, the compiler has to do a lot of inference, and if > the compiler gets it wrong, the resulting error messages tend to be > cryptic. This is why haskell's cryptic errors if you make syntax > mistakes is something many people think is a fundamental, unfixable > aspect of that language. Most latent languages allow you to specify if > you want to, though. > > The central argument between static v. dynamic usually boils down to: > Is it worth it. Types itself are easy, and between using latent typing > and the simple fact that you can't unit test comments, so moving > anything you'd stuff into a doc-comment in python into an explicit > typing system is always a good thing - seems to indicate Static is in > all ways superior to dynamic. However, to do it right, you need > generics, which have co- and contravariance, and this is where things > get rather complicated. Is it worth it to avoid cast bugs? Heck no, it > isn't. Cast bugs are rare, and the complexity introduced when you want > to do serious generics-fu is massive. That's the standard argument of > dynamic typing fans, and it shows that they don't understand what > static typing is for, because: > > Static typing is all about documentation (which fortunately WAS raised > in the roundup!) - you're going to have to document the structure of > what your method returns anyway, might as well do so in a way that the > compiler can help you out, and in a way you can test. Static typing > make auto-complete work. > > So the real question is: Is the considerable complexity of e.g. co/ > contravariance a fair cost compared to the value of having tool- > readable documentation about how your program chunks behave, which > those tools can use to do e.g. much smarter refactoring? It's question > for the ages - and I'm happy the discussion did eventually get around > to this. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "The Java Posse" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/javaposse?hl=en -~----------~----~----~----~------~----~------~--~---
