2004/03/31 19:15 EST (via web):
I'm sure you know, but the Python file reading example can be made even simpler and easier to remember: for line in file("FileName?.txt"): # Process line
Plus, I don't think language other than Python lets you swap the values of two variables like this: a, b = b, a
With your love for python, have you looked into Groovy? If so, what do you think of it? I would really love to see your thoughts on this new JVM language.
2004/03/31 22:10 EST (via web):
Very good! The only thing I can suggest is to please do give IDEA (or Eclipse, presumably) another try. It takes some gettting used to, and you might have to change your coding style and memorize some new keyboard equivalents. But it's an enormous productivity increase, almost like going from Java to Python. Navigating source trees becomes quick and easy, and you rarely have to look at reference documentation, even for API's you rarely use.
2004/04/01 01:48 EST (via web):
About swapping of values: Ruby is another language where you can swap variables like a, b = b, a. And how about this ary = [1, 2, 3]? a, b, c = *ary a => 1 b => 2 c => 3
First of all, my compliments for your Java Book, I have learned Java from it many years ago. I would have liked to buy the printed version, but here in Italy I had a hard time finding it, so I resorted to printing it on my printer... not optimal, but it worked :-)
In any case, my experience with Python is exactly the same as yours: it's definately more productive, but you gotta try it to understand. I have written part of the new Python based Gump (http://gump.apache.org/) and it has been very easy to hack on it. On the other hand, I find it a bit more opaque as time goes by, and maintainance doesn't seem so easy as it was to write it, although not bad at all. Because of this I've decided to write big programs in Java and script in Python or Jython. I really can't wait to use OpenOffice? with integrated Python scripting support!
2004/04/01 14:39 EST (via web):
'"I suppose you could argue that Java wasn't intended to do text processing"'
"In Python, which is a succinct language, ... Java is unashamedly verbose"
Whether a language has manifest concrete types or latent concrete types, and whether a language has manifest abstract types (interfaces) or latent abstract types (interfaces), is easily visible and obvious to everyone.
Being the most obvious difference, doesn't make it the most important difference (in terms of productivity). Is it type information in the Java syntax that makes it more verbose than REBOL; or is it that REBOL has 45 types built into the language syntax?
One dispiriting aspect of type fixation (explicit or implicit) is that we don't look at all those many other features that make a language succinct and expressive. ___________________________________________________________________________
2004/04/01 14:53 EST (via web):
'" "Latent Typing," a term that really does have history in computer science'"
It says what a language syntax doesn't have - typed variables - not what it does have.
"The term latent typing is used to describe a computer language, such as Scheme, for which you cannot, in general, simply look at a program's source code and determine what type of data will be associated with a particular variable, or with the result of a particular expression." http://www.gnu.org/software/guile/docs/guile-ref/Latent-Typing.html ___________________________________________________________________________
2004/04/01 17:16 EST (via web):
the experience of being dramatically more productive
It's the people and the process not the language!
"At the start I estimated the productivity advantage of Lisp/CLOS over C/C++ at a factor of three to four; at the end I set it at 30%. But I think this 30% is inherent in some languages, an advantage due to unpopular characteristics of those languages, such as dynamic types." p128
Patterns of Software, Richard P. Gabriel http://www.dreamsongs.org/NewFiles/PatternsOfSoftware.pdf
- - - - - - -
2004/04/01 17:50 EST (via web):
dogs and robots program one more time
The strangest thing about this program is that it seems we want to use talk() with any type of object - shouldn't we define speak() in Object, and override talk() where we want to have special behaviour?
So the problem isn't that Java has explicit types, it's that Java doesn't provide a modular way to extend classes without editing the original source code. Nice does allow talk() to be defined without editing the source for Object:
void talk(Object o){ println( o + " cannot talk"); } void speak(Object speaker){ speaker.talk; }
void main(String[] args){ new Dog().speak; new Robot().speak; new Mime().speak; }
Woof! Click! Mime cannot talk - - - - - - -
RE: intellectual vs. experiential crisis
On another intellectual note, I'm curious what impact the decreased productivity of coding in Java has on overall design, architecture, and maintainability. I've worked with many people who equate increased productivity with "license to hack".
Don't get me wrong; I'm in no way implying that being more productive means you are hacking. I'm just curious about the relationship and/or phenomenon.
I think that your argument about reading files line by line is fairly spurious because it assumes that you're starting over from scratch each time. If every time that you start a project, you start over from scratch staring at an empty screen, remembering that you need to open a BufferedReader? on a InputStreamReader? to get a convenient readLine(), that's pretty hard.
If at some point, you created a simple utility class that abstracted all that crap away so you could get an iterator over your file, that would reduce it to the much more palatable:
FileThingy f = new FileThingy("filename.ext"); Iterator i = f.iterator();
while(i.hasNext()) { String line = i.next(); }
I've found that accumulating these utility classes as I go takes away a lot of the advantage of writing something in Python, and it helps prevent the problems with bitrot over time once I've been far enough from the code that I forget its structure.
maybe it's not the strong static typing that's a burden on the productivity, but the way this strong static typing is achieved, the programmer has to do it manually, where it could be possible to deduct it
you know, you might have sold me on the single user productivity issue ... the faster you can get to testing real data in my experience the generally more productive I am.
How do you think this applies in large groups ? I realize you can create modules in Python, but I'm not sure they compare to the extra safety net that you get when you are constrained by static typing. I think those constraints are actually a mechanism that facilitates large group interworking & programming mechanics, but I would be curious to hear a rebuttal on the topic.
John.
see also: http://research.microsoft.com/~maf/talks/Berkeley-VAULT.ppt
A frequently overlooked problem with weak typing is the consequence for maintenance. I agree that if you type in a program it's faster to do this in Python than in Java. You don't need to type the types, and you can change them without changing the source. You don't need to declare interfaces either, just implement the methods. But that's only possible because you have them in your mind. You don't type them, but they are still there.
If you look at the program a year later, or someone else wants to fix a bug or add a feature, the lack of types becomes a problem. In order to find out the type of a function argument and thus how you can use it, you need to look at all invocations and find out the types from all invocations. This may be a recursive process, because the types in the invocation may be implicitly defined as well. If you are using implicit interfaces aka duck typing, you need to look at all these types and find out which methods the types have in common. It's a time-wasting and error-prone effort for what takes a few seconds in a strongly typed language.
The alternative, of course, is to document precisely the type of every argument or which properties it needs to have. But that's the same as static typing, only in a free text and thus not compiler-readable. I'd prefer a formal syntax every time.
-- Right, it's the self-documenting code aspect that it seems few people I know care about. Bruce included. Does he use some kind of hungarian notation to indicate the type of his objects? Is he an elephant that never forgets?
One thing that perhaps makes typing so important in C++ versus C is that the objects you're playing with are so dangerous.
If you bugger something up in Python (or even Java, by casting it to the wrong object), then you'll get an exception, you might be able to catch it and go on. If you bugger it up in C or C++ then you're trashing memory and might cause all sorts of weird and wonderful errors later that you can't trap. Because of the safety net of the JVM/Python managed environments, maybe this is one of the reasons that typing is less important now?
======================================================================================================
2004/04/06 11:10 EST (via web):
At last, Bruce Eckel accept that Java is Java. "In the end, I've realized that the requirement that you have to use interfaces everywhere really isn't that big of a deal. (...) Requiring a few extra interfaces here and there is not much of an impact on the resulting code, and is indeed in keeping with the Java language philosophy." Surprising to hear this "revelation" from a supposed Java expert. What annoys me is that Bruce goes on to accuse Java defenders of arguing "in the abstract". Bruce has now written four long articles and given a keynote speech but up to now he hasn't come up with a single real world example of how Java types hurt productivity. I don't know Python. Maybe Bruce is right but so far he hasn't provided a single convincing argument (the file-read example, of course, has nothing to do with latent typing. It's a nice shorthand notation, "syntactic sugar"; as far as I understand, a similar shorthand will be introduced in JDK 1.5.), and worse, he hasn't responded to any of the counterarguments. The most important argument for the Java interface requirement, enhanced maintainability, has been cited many times. Bruce simply ignores it. Maybe he sincerely doesn't understand it because the big projects he's boasting about ("if you want to get a lot done, use Python") are really one-person projects where maintainability seems (sic!) not to be a big issue ("is he an elephant that never forgets?"). My experience is that in most projects, maintainability is really the big issue. The idea that writing a few more lines of code to clarify your intention might hurt productivity has, in fact, never crossed my mind. I wonder how Python code is maintained. Okay, this might be "arguing in the abstract". But I don't make claims about Python. Bruce makes claims about Java, and it's up to him to prove them. Thus far, he has failed.
Toni Menninger
2004/04/06 11:13 EST (via web):
Hey folks! There's a "with heading" checkbox on the bootom of the form which can be easily overlooked. Check it to enhance readability and maintainability if this discussion! (Why isn't this the default???)
-
2004/04/06 11:14 EST (via web):
-
2004/04/06 13:13 EST (via web):
'bugger something up in Python... or even Java... then you'll get an exception... bugger it up in C or C++ then you're trashing memory... one of the reasons that typing is less important now?'
Some languages are TYPE SAFE. All errors are trapped - either at compile-time or at run-time.
Not safe: BCPL family, including C and C++ • Casts, pointer arithmetic
Almost safe: Algol family, Pascal, Ada. • Dangling pointers. – Allocate a pointer p to an integer, deallocate the memory referenced by p, then later use the value pointed to by p – No language with explicit deallocation of memory is fully type-safe
Safe: Lisp, ML, Smalltalk, and Java • Lisp, Smalltalk: dynamically typed • ML, Java: statically typed _________________________________________
2004/04/07 22:13 EST (via web):
Java requires more effort to write some things, period. The jury is still out if the effort is really worth it.
NN
Java example:
public interface Walk {String walk();}
public interface Sing {String sing();}
public interface Speak {String speak();}
public interface SpeaknSing extends Speak, Sing {}
public interface SingnWalk extends Sing,Walk {}
public interface SpeaknWalk extends Speak, Walk {}
public interface SpeaknSingnWalk extends Speak, Sing, Walk {}
public class Computer implements SpeaknSing {
public String speak() {return "hello";}
public String sing() {return "beep, beep";}
}
public class Dog implements SpeaknSing, SingnWalk, SpeaknWalk, SpeaknSingnWalk {
public String speak() {return "wof";}
public String sing() {return "aaaauuuu";}
public String walk() {return "tap, tap, tap";}
}
public class Duck implements SpeaknWalk {
public String speak() {return "quack";}
public String walk() {return "chap, chap, chap";}
}
public class RunIt {
public static void broadway(SpeaknSingnWalk someone){
System.out.println(someone.sing());
System.out.println(someone.walk());
System.out.println(someone.speak());
}
public static void choir(Sing someone){
System.out.println(someone.sing());
}
public static void hike(SingnWalk someone){
System.out.println(someone.sing());
System.out.println(someone.walk());
}
public static void theater(SpeaknWalk someone){
System.out.println(someone.speak());
System.out.println(someone.walk());
}
public static void main(String[] args) {
Computer computer=new Computer();
Dog dog=new Dog();
Duck duck=new Duck();
broadway(dog);
choir(dog);
choir(computer);
hike(dog);
theater(dog);
theater(duck);
}
}
Python example:
class Computer:
def speak(self): return "hello"
def sing(self): return "beep, beep"
class Dog:
def speak(self): return "wof"
def sing(self): return "aaaauuuu"
def walk(self): return "tap, tap, tap"
class Duck:
def speak(self): return "quack"
def walk(self): return "chap, chap, chap"
def broadway(someone):
print someone.sing()
print someone.walk()
print someone.speak()
def choir(someone):
print someone.sing()
def hike(someone):
print someone.sing()
print someone.walk()
def theater(someone):
print someone.speak()
print someone.walk()
computer=Computer()
dog=Dog()
duck=Duck()
broadway(dog)
choir(dog)
choir(computer)
hike(dog)
theater(dog)
theater(duck)
2004/04/08 10:47 EST (via web):
In the example above, the difference between Java and Python boils down to the definition of seven interfaces in Java (one line of code each). For those seven lines, you get the benefit of a compiler error if you try to make a computer walk, and equally important, you or the person who will then be responsible will easily understand the code years later. Do the seven additional lines of code hurt productivity? The typing can hardly be the problem. If anything, it would be the fact that you have to develop the abstractions in your head before writing them down as interfaces. Does it hurt productivity to think about your object model before coding it? Maybe this question is the essence of the latent typing dispute. I argue that even if you don't write your abstractions down, you have to grasp them. Even in the Python program, the idea exists that some objects can sing and walk, and others can only sing but not walk. But as those ideas remain "latent", you have to form them in your head each time you read the code. The error, in my opinion, is to think that you can save time by not writing down the ideas you have in your head. I prefer to write down as much as possible rather than unnecessarily burdening my mind.
Toni Menninger
2004/04/08 10:58 EST (via web):
the difference between Java and Python boils down to the definition of seven interfaces
Seven interfaces for 3 methods! Do you think that scales?
_______
2004/04/12 11:32 EST (via web):
You don't grasp it. You don't need an interface for each method, you need one for each abstraction. What I tell you is that whether you use Python or Java, you have the same abstractions. Whether you specify them explicitly or not, they are still there and you have to deal with them. "Do you think that scales?" The above example with seven interfaces is artificial; in any real life scenario, the ratio of interfaces to code volume will be much more modest. Too many abstractions might indicate bad design.
Toni
2004/04/12 14:47 EST (via web):
I just want a language with TypeInference? to become popular. Type inference combines the advantages of static typing (program speed, safety) with those of dynamic typing (programmer speed, conciseness). Take a look at Haskell and SML, kids. The requirement to specify the types of every variable and object you working with when the compiler should be perfectly able to figure out what they're for is, well, pointless. And before anybody starts shouting that inference hurts object code performance, look at O'Caml: the performance of its object code is right up there with C and C++.
With Java, you feel as if you're talking to an idiot savant. You have to spell things out, things capable of being inferred from context. A programmer just shouldn't have to do this. This really does hurt productivity: you're getting the programmer to do things they shouldn't need to. With Python, OTOH, you've got a smart kid that can guess what's going on, but might be a bit slow because of the way they do it, having to check context. Continually.
Only we're talking about code that's compiled, and compiled once. All the checking that Python does can, when it's compiled, be done once and once only. StarKiller?'s rather neat. It's an attempt to bring the benefits of type inference to Python.
2004/04/14 11:54 EST (via web):
"I just want a language with Type Inference to become popular"
Nice http://nice.sourceforge.net/index.html and Scala have local type inference; and they compile to ordinary jvm bytecodes.
_____
2004/04/14 12:00 EST (via web):
'"You don't need an interface for each method, you need one for each abstraction"'
We need to create a multitude of interfaces that may never be used, to support the claim that "the difference between Java and Python boils down to the definition of seven interfaces".
_____
2004/04/15 09:52 EST (via web):
<
Toni Menninger
2004/04/15 10:36 EST (via web):
Then I apologize for thinking it was (2004/04/08 10:47 EST).
2004/04/16 10:20 EST (via web):
I would have preferred to discuss the issues, rather than do line counting. Anyway. Somebody above suggested that Nice supports local type inference. Lest there be more confusion, I should point out that type inference in the Nice sense has nothing got to do with latent typing in the sense introduced by Eckel. Nice doesn't support anything like
choir(someone){ someone.sing();}
In fact, according to the designer of the language, Nice is as type-safe as it gets. Eckel has claimed, or I understood that he claimed, that Python code as in the example above was in fact type-safe. This is not the case. As Pixel (http://diary.recoil.org/pixel/archives/000193.html) has demonstrated, it is not possible that the types of all objects can be known at compile time if they are not stated explicitly.
Toni Menninger
2004/04/16 16:13 EST (via web):
Type Safe So what do we mean by that?
"Type safety is the property that no primitive operation is ever applied to values of the wrong type."
Many dynamically checked languages are type-safe, see the 2004/04/06 13:13 EST posting above.
______________
2004/04/16 16:20 EST (via web):
"Nice doesn't support anything like"
In Nice abstract interfaces provide a way to express that there's a kind of type that has a sing method, and that the parameter someone is that kind of type (and be statically-checked - which is not the same as type-safe).
2004/04/19 13:35 EST (via web):
What did I mean by "Type Safe" in my post about Nice? I actually used it in the sense of "static type safety" (see for example http://nice.sourceforge.net/safety.html). If you argue that Python is type safe because it throws a RuntimeException? instead of crashing the machine if something has no sing method, then I guess you are right. But our dispute, I think, is about whether it is preferable to specify object types at compile time (even if it involves a couple of lines of additional code) or whether this is just unnecessary hassle. You have been praising Python for the freedom to pass "anything" to any method unchecked; I praise Java and Nice for restricting this freedom. Local type inference at compile time is a separate case that shouldn't be mixed with the argument about "latent typing".
Maybe you could post a code example to show us how the sing example would work in Nice. Looks like it might involve some lines of code ("express that there's a kind of type that has a sing method, and that the parameter someone is that kind of type") but it sure would be interesting.
Toni
So why don't you post the code example in Nice? I'm quite certain that my point about Nice is correct but you might convince me of the opposite.
2004/04/19 14:21 EST (via web):
"Type Safe" these days I try and follow the definitions used in school courses - http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/
These unsigned posts are confusing - I mentioned local type inference because some one asked about it, I don't use Python so I neither praise nor condemn it.
There's a relevant code example at the bottom, here: http://diary.recoil.org/pixel/archives/000194.html
Isaac _____________
"Its a shame Bruce decided not to talk about testing and maintenance. I'd have liked to have seen some more of his perspective. I wonder if project size & number of team members make a significant difference to when the benefits of using explicit interfaces kicks in."
Pixel
2004/04/19 15:25 EST (via web):
"Its a shame Bruce decided not to talk about testing and maintenance. I'd have liked to have seen some more of his perspective. I wonder if project size & number of team members make a significant difference to when the benefits of using explicit interfaces kicks in."
Pixel
2004/04/19 15:29 EST (via web):
"These unsigned posts are confusing" - Yes indeed. Is it Isaac who wrote this? Are you the guy who mentioned Nice?
2004/04/19 15:41 EST (via web):
There's a code example at the bottom of http://diary.recoil.org/pixel/archives/000194.html but it doesn't explain what language it refers to (if any). I assume it is Nice. In this example, it takes as many interfaces as it would take in Java. The "sing"-example in Nice would still need the seven interfaces. But a class can retroactively be declared to implement an interface. Very interesting. Still, as stated before: "Nice doesn't support anything like
choir(someone){ someone.sing();}
Toni
2004/04/19 23:37 EST (via web):
Pixel! Can we add some comments to your blog, please? Isaac
2004/04/20 02:42 EST (via web):
in Nice would still need the seven interfaces No.
// Nice_________________interface ISing { String sing(); } interface ISpeak { String speak(); } interface IWalk { String walk(); }
class Computer implements ISing, ISpeak { speak() = "hello"; sing() = "beep, beep"; }
class Dog implements ISing, ISpeak, IWalk { speak() = "wof"; sing() = "aaaauuuu"; walk() = "tap, tap, tap"; }
class Duck implements ISpeak, IWalk { speak() = "Quack"; walk() = "chap, chap, chap"; }
void main(String[] args){ let computer = new Computer(); let dog = new Dog(); let duck = new Duck();
broadway(dog); choir(dog); choir(computer); hike(dog); theater(dog); theater(duck); }
<T | T<:ISing, T<:IWalk, T<:ISpeak > void broadway(T someone){ println( someone.sing ); println( someone.walk ); println( someone.speak ); }
void choir(ISing someone){ println( someone.sing ); }
<T | T<:ISing, T<:IWalk > void hike(T someone){ println( someone.sing ); println( someone.walk ); }
<T | T<:IWalk, T<:ISpeak > void theater(T someone){ println( someone.speak ); println( someone.walk ); }
<T | T<:ISing, T<:IWalk > void hike(T someone){ println( someone.sing ); println( someone.walk ); }
<T | T<:ISing, T<:IWalk, T<:ISpeak > void broadway(T someone){ println( someone.sing ); println( someone.walk ); println( someone.speak ); }
<T | T<:IWalk, T<:ISpeak < void theater(T someone){ println( someone.speak ); println( someone.walk ); }
<T | T<:ISing, T<:IWalk> void hike(T someone){ println( someone.sing ); println( someone.walk ); }
Please feel free to add tags to that code.
2004/04/20 09:46 EST (via web):
Confusing. Does the
2004/04/20 09:47 EST (via web):
"Two things make an abstract interface different from a regular interface. First, a class can be made to implement an abstract interface after it's been defined, and even the source code is unnecessary. You can make the basic String class implement your new abstract interface, if you like. Second, an abstract interface is not actually a type, it's an annotation which can be applied to types. This means that when you declare an abstract interface, you're not creating a new type, you're saying "types which implement this abstract interface will all have these methods", but those types are not related in any other way." http://nice.sourceforge.net/manual.html#abstractInterfaces
2004/04/20 10:16 EST (via web):
I understand that in the Nice example, you define three Java-type interfaces and three abstract interfaces. Is that right? So Nice certainly gives you more flexibility and expressiveness. Still, fortunately, it's not latent typing - static type safety is preserved. There's also no significant reduction in code volume, not in this example. Can we all agree an that? Could we agree that Nice demonstrates that you don't have to weaken type safety in order to achieve more expressiveness?
Toni
2004/04/20 10:25 EST (via web):
Sorry, three type variables, not abstract interfaces.
2004/04/20 13:31 EST (via web):
For variety the example makes use of ordinary interfaces and parametric methods - maybe we can do this with Java 1.5 (does it provide multiple bounds?). So 3 Java type interfaces and 3 static methods parameterized by multiple type bounds (the 4th static method accepts a single interface).
"weaken type safety" Again, most dynamically checked languages are type-safe.
Isaac ______________
2004/04/20 13:34 EST (via web):
// Niceinterface ISing { String sing(); } interface ISpeak { String speak(); } interface IWalk { String walk(); }
class Computer implements ISing, ISpeak { speak() = "hello"; sing() = "beep, beep"; }
class Dog implements ISing, ISpeak, IWalk { speak() = "wof"; sing() = "aaaauuuu"; walk() = "tap, tap, tap"; }
class Duck implements ISpeak, IWalk { speak() = "Quack"; walk() = "chap, chap, chap"; }
void main(String[] args){ let computer = new Computer(); let dog = new Dog(); let duck = new Duck();
broadway(dog); choir(dog); choir(computer); hike(dog); theater(dog); theater(duck); }
<T | T<:ISing, T<:IWalk, T<:ISpeak > void broadway(T someone){ println( someone.sing ); println( someone.walk ); println( someone.speak ); }
void choir(ISing someone){ println( someone.sing ); }
<T | T<:ISing, T<:IWalk > void hike(T someone){ println( someone.sing ); println( someone.walk ); }
<T | T<:IWalk, T<:ISpeak > void theater(T someone){ println( someone.speak ); println( someone.walk ); } //---------------------
2004/04/20 15:08 EST (via web):
"Again, most dynamically checked languages are type-safe." I think it is fair to say that dynamic type safety is weaker than static type safety (1). "Type safety" in the sense of "at least it doesn't crash the system" is certainly a progress when compared to what you can do in C, but for me, "safety" implies a little more than that. I'm with Bonniot.
Toni
(1) Bruce Eckel, Thinking in Java, 3d edition, p. 325: "If you do want extra type safety..." What can "extra type safety" mean if the language by definition is already type safe?
2004/04/20 15:15 EST (via web):
Now that's some nice Nice code. For the record, it's one line shorter than the Java code. Except, doesn't the main method need to belong to a class?
The formatting in this wiki is getting worse and worse.
2004/04/20 15:25 EST (via web):
formatting... worse and worse Apologies for my contribution to that - so much easier with preview & brief tag notes & a decent size comment box.
Nice allows static methods/functions (and variables/constants) to be defined in a package (main, broadway, choir, hike, theatre are all package level).
line counting - but is it easier to understand than the Java code? Isaac __________________________
2004/04/20 15:35 EST (via web):
type safety is weaker Let's try and keep some distinctions crisp. A language is type-safe or it isn't - otherwise we fall-into special pleading.
We can still discuss the benefits/costs of finding errors at compile time vs finding errors at runtime, but let's not confuse that with type-safety.
(Not sure that Bruce claims to be an authority on type systems, meanwhile let's prefer the judgement of Cardelli and Krishnamurthi.) ______________
2004/04/21 09:59 EST (via web):
"but is it easier to understand than the Java code?" Not in my view, but I guess this depends on how familiar the language is. I said that Nice is more expressive than Java but I'm not sure how useful those features really are. In any case, I wouldn't recommend them if they make the code more confusing and less readable. But I cannot judge.
"let's not confuse that with type-safety" I don't agree. If almost every modern language is by default type-safe, and almost everybody agrees that type safety is a must, then the concept becomes meaningless. It would be meaningless for Bonniot to discuss "Type safety in Nice" (http://nice.sourceforge.net/safety.html). I think it's legitimate to take the concept further and to distinguish strong vs. weak/static vs. dynamic type safety. I also think that your strict usage of the term is unintuitive: "safety" implies more than "throw a RuntimeException?". The effect of a "type-safe" failure is often indistinguishable from an "unsafe" failure (if not, blame the operating system). And the question is not only when to find errors but whether to find them at all (there's a difference between "observing a runtime failure" and "finding an error"). - But I will have a look into Krishnamurthi anyway.
Toni
2004/04/21 10:01 EST (via web):
"but is it easier to understand than the Java code?" Not in my view, but I guess this depends on how familiar the language is. I said that Nice is more expressive than Java but I'm not sure how useful those features really are. In any case, I wouldn't recommend them if they make the code more confusing and less readable. But I cannot judge yet.
"let's not confuse that with type-safety" I don't agree. If almost every modern language is by default type-safe, and almost everybody agrees that type safety is a must, then the concept becomes meaningless. It would be meaningless for Bonniot to discuss "Type safety in Nice" (http://nice.sourceforge.net/safety.html). I think it's legitimate to take the concept further and to distinguish strong vs. weak/static vs. dynamic type safety. I also think that your strict usage of the term is unintuitive: "safety" implies more than "throw a RuntimeException??". The effect of a "type-safe" failure is often indistinguishable from an "unsafe" failure (if not, blame the operating system). And the question is not only when to find errors but whether to find them at all (there's a difference between "observing a runtime failure" and "finding an error").
- But I will have a look into Krishnamurthi anyway. Toni
2004/04/21 11:50 EST (via web):
your strict usage of the term
I'm just falling into line with the type system professionals.
every modern language is by default type-safe
And here's where we get into special pleading - by default type-safe?
So they are type-safe except when they aren't type-safe?
When we mean type-safe and statically-checked, let's say so!
The effect of a "type-safe" failure is often indistinguishable from an "unsafe" failure There's a huge difference between raising a runtime error and letting the program silently trash the system. Don't we know that from unchecked buffer-overflows?
Tony Hoare on implementing Algol 60 (in 1961)
"(1) The first principle was security: ... A consequence of this principle is that every occurrence of every subscript of every subscripted variable was on every occasion checked at run time against both the upper and the lower declared bounds of the array.______________________Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to - they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous."
2004/04/21 14:55 EST (via web):
I don't want to quarrel with you, only it's a fact of life that terms like "type safety" aren't used exactly in the same way by everyone. I agree that we all should be as precise as possible, thus I will in future use the terms static/dynamic type safety, only I don't like the attitude "there's a book where X is defined so und so, you don't stick to this definition so you are wrong". I'm not the only one who uses the term in a broader sense than you do.
By the way, even pure mathematicians sometimes don't agree about certain definitions, or they have to refine definitions that already exist in the literature, or there exist different versions of the same definition (sometimes called "weak" and "strong"). By the way, who are you?
Toni
2004/04/21 17:13 EST (via web):
quarrel
Arguing about terminology quickly becomes old ;-)
As long as we have a commitment to understanding and being
understood we can always agree on terms.
Isaac Gouy _____________________
2004/04/22 11:48 EST (via web):
"Arguing about terminology quickly becomes old ;-)" Having agreed on that, do you have anything to add on the subject of this discussion? Should we conclude it? Have we learnt anything from it ;-) ?
Toni
2004/04/22 12:03 EST (via web):
We could find things to disagree about, but this isn't a discussion forum. I learnt how to format text for this wiki! How about you?
best wishes, Isaac ______________
2004/04/22 13:36 EST (via web):
"this isn't a discussion forum" - in fact, it hasn't been used as a discussion forum but that's up to the users. However, it's certainly not a wiki - or would you like to quarrel about the exact definition of a wiki?
Be Krishnamurthi with you ;-) Toni
2004/04/22 15:03 EST (via web):
would you like to quarrel about the exact definition of a wiki? I'd just check the OED ;-)
There are Nice examples on their wiki http://nice.sourceforge.net/cgi-bin/twiki/view/Doc/CodeExamples
Au revoir! __________
2004/04/27 00:17 EST (via web):
Sometimes I like that Java is explicit, but many times I curse it for having this anal and idiotic compiler that can not figure out on its own that my code is perfectly sound. Each time I say: Integer i=new Integer(); I feel like I am talking to my Grandfather having to say everything twice until he understands. What type could
i possibly be of if I am saying new Integer(); Gosh!I would very much prefer a type inference engine a la O'caml or Haskell with optional type declaration when I really want to be explicit. If I can easily figure out that the code is safe by looking at the code the compiler should be able to figure it out too.
Now for Python I do not know how well it would work. One of the advantages of Python is that I can take a 2000 line program and instantly run it, great for fast turnaround. Type inference engines I heard of usually work for traditional compilers. Now I think O'caml has an interactive shell so maybe it is technically possible to have a really interactive experience using type inference. But if I am interpreting one line at a time, would that be any different from how Python works now? Maybe it is something to include in Pychecker?
As far as the code example. You do not usually start writing code like that in Java. You usually find out with time that you need to refactor some of the interfaces later on. The example is just what it would require to get the equivalent flexibility of the Python example in Java.
A more interesting exercise would be seeing somebody translate a real world example like
this
to Java? Notice how the parameter s of unique() could be almost anything. Anybody up to the task?
Nestor
2004/04/27 12:20 EST (via web):
Interesting example, but in my view still rather academic. As the author puts it, it shows "how algorithm efficiency depends on the strength of the assumptions you can make". It turns out that in Java, one can make strong assumptions: all Objects support equals() and hashCode() (also true for arrays but they only support the trivial version of equals()). Let's say I have a List l of hashable objects, I would just return
new ArrayList( new HashSet( l)).
If it is an array of a, it would be new HashSet( Arrays.asList( a)).toArray().
No need to write an extra method for this simple operation, is there?
The above code works for any Java Collection and any Object array. It only fails if the hashCode() implementation
doesn't fulfill the contract (typically if equals() has been overwritten but not hashCode() ).
In that case, duplicates wouldn't be eliminated. This of course can't be detected neither at compile- nor at runtime.
The only case that isn't covered in the above code are primitive types. To make the example work, an int[] array would have to be converted to an Integer[] array. This is a well-known drawback of Java.
Toni
If it is an array a, not "an array of a".
2004/04/27 17:06 EST (via web):
To make it more comparable, here a Java implementation that works with any Collection or Object array (arrays of primitives could be added with some additional effort):
public Object removeDuplicates( Object c){
if ( c instanceof Collection)
return new ArrayList( new HashSet( (Collection) c));
else if ( c instanceof Object[])
return new HashSet( Arrays.asList( (Object[]) c)).toArray();
else throw new IllegalArgumentException( c.getClass().toString());
}
It can be done, but there's no good reason to do it - it doesn't make sense. You don't know what you will get back, you will have to cast it in any case and probably have to transform it to a List or whatever it is you really want. What would otherwise be one line of plain Java code - adapted to a specific purpose - becomes a confusing and unsafe method call plus a cast. Moreover, when I need a collection without duplicates, it is likely that I will choose a Set right from the beginning.
Maybe this "one size fits all" kind of approach is natural in the Python world; in Java, there's no place for it.
Toni
2004/05/07 22:08 EST (via web):
I wonder if Java-the-JVM supports latent typing, while Java-the-source-language doesn't. There's a JVM bytecode that calls a method "by interface", and AFAICT the method is just a method-signature and doesn't really have to belong to a specific interface. So maybe Dogs and Robots can speak() or talk(), but only for the JVM, not for the current definition of the source language.
So maybe what we need is less Java and more JVM.
2004/05/10 10:43 EST (via web):
What do we need Java for anyway? Maybe Java doesn't exist at all. It's an illusion. It's all virtual. Maybe the brain is a virtual machine.
I was beginning to think that Bruce gets it, but then I read "So I understand that Java generics are really just autocasting for nicer use of containers, and that's good and useful and it doesn't go any further than that. The generics chapter of Thinking in Java, 4e will thus be easier to write (nothing really complex will happen as in Thinking in C++, volume 2)."
I think Bruce now better understands (though doesn't appreciate) the spirit of the Java programming language both with and without the generics extension, but I think he will do his readers a real disservice if he leads them to believe that generics are just for containers and eliminating casts. They're part of the type system, Bruce! Read Bracha's generics tutorial.
2004/05/23 13:12 EST (via web):
"For variety the example makes use of ordinary interfaces and parametric methods - maybe we can do this with Java 1.5 (does it provide multiple bounds?)." - Isaac
Here's the walk, speak, and sing example redone to take advantage of Generics (could someone please add tags?):
interface Walk {String walk();}
interface Sing {String sing();}
interface Speak {String speak();}
class Computer implements Speak, Sing {
public String speak() {return "hello";}
public String sing() {return "beep, beep";}
}
class Dog implements Speak, Sing, Walk {
public String speak() {return "wof";}
public String sing() {return "aaaauuuu";}
public String walk() {return "tap, tap, tap";}
}
class Duck implements Speak, Walk {
public String speak() {return "Quack";}
public String walk() {return "chap, chap, chap";}
}
public class RunIt {
public static void main(String[] args) {
Computer computer=new Computer();
Dog dog=new Dog();
Duck duck=new Duck();
broadway(dog);
choir(dog);
choir(computer);
hike(dog);
theater(dog);
theater(duck);
}
public static <T extends Speak & Sing & Walk> void broadway(T someone) {
System.out.println(someone.sing());
System.out.println(someone.walk());
System.out.println(someone.speak());
}
public static void choir(Sing someone) {
System.out.println(someone.sing());
}
public static <T extends Sing & Walk> void hike(T someone){
System.out.println(someone.sing());
System.out.println(someone.walk());
}
public static <T extends Speak & Walk> void theater(T someone) {
System.out.println(someone.speak());
System.out.println(someone.walk());
}
}
David
2004/05/27 13:54 EST (via web):
Thanks. I see no difference with the Nice example from 2004/04/20 13:34 EST. Am I right or did I miss something?
2004/06/01 20:37 EST (via web):
They're very similar, but slightly different. For example, where Nice has "[T | T[:ISing, T[:IWalk, T[:ISpeak ]?", Java 1.5 has "[T extends Speak & Sing & Walk]?". (again, I don't know how to do angle brackets in wiki)
David
2004/06/02 09:43 EST (via web):
Interestingly, in the Java 1.4. example, seven interfaces were needed. With 1.5. generics, there's much more flexibility.
A lot of Bruce's arguments seem to be based on a situation where one solitary coder has a sudden need for a new program, and needs to create a quick solution to that and that's basically it. I do not know what kind of projects Bruce is involved with, but to me the given arguments pro Python / latent typing and con Java / fixed typing are really not relevant at all. For the "typical" situations where Java is used the time that getting code to run first time is not really that important. With projects having lots of developers that need to be able to communicate, and typically what, 80-90% of effort going into maintenance, readability and maintainability are what counts. Arguments against Java's verbosity and "since coders produce at average 10 lines of code per day so I want those 10 lines to contain as much functionality" borderline on stupidity...
I think the main difference is between compile time and run time checks. The compiler checks all the code, the run time systems checks just along the paths it encounters. I stress the notion path, because this means just making sure that every statement executed at least once will not suffice. Instead you are concerned with the execution of every statement in every reachable system state - this is normally infinite. Thus, when you end your tests you know there will be still further cases that might have been considered. At the end of the compiler run, you know that everything checkable by the compiler was checked indeed. Now, when you shipped your system to your users, they will certainly not appreciate that the run time error which hit them in the middle of their work and left them with possibly corrupted data, just means that the type checking succeeded in the end. For you, this means you have to fix the bug, do a new system test (which may be relatively cheap due to automation) and distribute a bug warning and the fix to all your users. When reasoning about productivity you need take all these efforts into accout as well. And the news about the bug will not improve your position in the market. So, I think that you can tolerate quite a lot of trade off in programming productivity for a more thorough compile time checking.
subtopics:
|