The Artima Developer Community
Sponsored Link

Weblogs Forum
Graceful Failure

53 replies on 4 pages. Most recent reply: Aug 30, 2005 2:50 PM by Gregg Wonderly

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 53 replies on 4 pages [ « | 1 2 3 4 | » ]
David Hall

Posts: 4
Nickname: dhall
Registered: Jul, 2005

Re: Graceful Failure Posted: Aug 23, 2005 7:35 PM
Reply to this message Reply
Advertisement
@Howard:

Thanks for taking the time to think about the problems and putting the suggestion together.


you could suggest that everyone uses the static factories and supplies the type in all cases, this way all declarations have the same syntax.


I think that would limit the audience for the library. The common syntax is fairly well understood by a sizable portion of the potential users, and is fairly well covered in the community wide discussion of generics syntax. The other usage is not terribly well covered, and thus it looks unusual the first dozen or so times you see it in use. I think that associating an API with the unusual usage will cause a certain number of potential users to discard the API in search of something else. It's already too common for a third party library to be rejected for fairly trivial reasons, I'd hate to give anyone the "You can't use the standard generics syntax -- you have to use that wierd prefix form" excuse.

In this part of your code ...
@SuppressWarnings( "unchecked" )
public Less( final Class< T > clazz ) {
    this( (Comparator< T >)naturalComparator ); // Unchecked cast - OK - ignore
    if ( !Comparable.class.isAssignableFrom( clazz ) ) 
        throw new IllegalArgumentException( "Given class, " +  
            clazz.getName() + ", does not implement Comparable" );
}
    
public static < T > Less< T > instance( final Class< T > clazz ) {
    return new Less< T >( clazz );
}


... you've accepted runtime type checking in place of compile-time type safety. I prefer not to do that in general, although I've had to resort to it in a few cases. In the cases where I've had to use this fallback, I do tend to do it as you've done it here -- throw IllegalArgument at construction rather than allow the implementation to throw ClassCast when the object is later used.

The static builder method could be rewritten as:

public static < T extends Comparable< ? super T > > Less< T > instance( final Class< T > clazz ) 


which would regain the compile-time type safety in the build method, while still accepting a lack of type-safety in the constructor. I think users would (rightfully) question why they have to pass the class argument to a type-safe method in order to support a redundant runtime check.

BTW: I've seen places where you've mentioned jga in discussions, and I wanted to tell you how much I appreciate having another voice occasionally talking about the library.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Graceful Failure Posted: Aug 23, 2005 10:01 PM
Reply to this message Reply
> > The real struggle isn't between static type checking
> > and dynamic type checking - the real struggle is against
> > software bugs.
> >
> > The more ways we have to prevent and identify software
> > bugs the better - we know static type analysis will
> > find software bugs we missed after years of testing and
> > use.
>
>
> This particular language feature seems to be not only not
> finding the bugs, but obscurring them. I have to question
> its value in light of this.

Todd, if you check the references I provided, you will see that they demonstrate static type analysis for existing applications written in a dynamically type checked language - Erlang - without requiring any change to the source code.

How does that not find the bugs?
How does that obscure bugs?

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Graceful Failure Posted: Aug 23, 2005 11:10 PM
Reply to this message Reply
I personally think there are a lot of possibilities to be mined in the area of automatically searching for particular coding patterns that may reveal buggy regions of code.

Microsoft Static Driver Verifier
http://www.microsoft.com/whdc/devtools/tools/sdv_facts.mspx

David Gates

Posts: 4
Nickname: dagates
Registered: Jul, 2005

Re: Graceful Failure Posted: Aug 24, 2005 5:30 AM
Reply to this message Reply
"You must have the necessary knowledge to figure out this message because you aren't given any help at either compile time or runtime."

The necessary knowledge is in PriorityQueue's documentation:
"A priority queue relying on natural ordering also does not permit insertion of non-comparable objects (doing so may result in ClassCastException)."

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Graceful Failure Posted: Aug 24, 2005 3:51 PM
Reply to this message Reply
@David Gates:

I agree with your observation about the error message being obscure, in my classes I pass in the class as an argument to the constructor so that I can generate the error when the collection is made instead of when the collection is used. This unfortunately wasn't an option for Sun since they wanted backward compatability with a previous version. An improvement they could consider for the future, as you suggested in a previous post, is to add a static factory. However, they have provided the wrappers in Collections that do extra type checking by accepting the class as an argument, these are handy if you get the error message that Bruce got.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Graceful Failure Posted: Aug 24, 2005 4:33 PM
Reply to this message Reply
@David Hall:

I agree with your sentiment that people will reject something new (not just a third party library) for the most trivial reason and therefore you need to be careful about doing something even a little bit different. Your example of using a less common syntax is a good example of this unreasoned rejection another is the general generics debate (just because they can find one exception were generics didn't work they reject the whole concept).

With regard to your library I think you have done an excellent job, so I have no problem mentioning it in posts or recommending it to people. I also think you are wise in sticking to your way of doing things so that your library is consistent and has a style. The same can be said for the collections library, it is self consistent and has a style, and therefore I am happy with this too. In both cases I would probably have done some things differently, but these changes I would make are more a matter of style than substance and therefore I don't feel the need to write my own APIs (just use those that already exist).

Java generics are also a particular implementation of the concept that have good and bad features from my point of view. But just because I would do things differently doesn't make them unusable. In fact quite the opposite, I find them very useful. For me they are a considerable improvement over C++ templates for example. I also like the fact that they are extremely compatable with the past, which I find most useful.

As an example of a style change I would make to your library; I wouldn't bother with the
Comparable< ? super T >
specification, I would just use
Comparable< T >
or the runtime check I suggested in the constructor. I know Sun needs to use
Comparable< ? super T >
to remain compatible with the past, but I can't see the value of comparisons accross derived classes so taking away the compatability constraint I would use a different signature. So with your
java.sql.Time
example I would use a
java.lang.Date
comparator and hence not need the
Comparable< ? super T >
specification. So I would have done things a little differently, but this is such a trivial difference that it hardly seems worth not using the library for.

However I do accept that people will reject the library, or anything else for that matter, for the most trivial reasons. To me it is like a religious war were they fight over a minor difference in interpretation of the same text!

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Graceful Failure Posted: Aug 24, 2005 5:13 PM
Reply to this message Reply
@Isaac Gouy:

> It may be spurious for other reasons, but I think you've
> missed part of the argument - it's a complaint that we
> paid for static type checks but didn't get them, with the
> 'dynamic language' we didn't pay for static type checks
> and didn't expect to get them.

I guess that typing List< String > names instead of just names is no big deal to me, so that if it gets 99% of the errors I am happy and I think I got good value for my 12 keystrokes.

Similarly I tend to use whitespace in my code, e.g. instead of List<String>names I use List< String > names, and I also tend to use medium length names like names instead of n. I also generally include a Javadoc comment for public methods and write some test code. Many people find all of this too much trouble and I suspect that these people are the ones that don't want to type their programs and therefore are almost actively looking for a reason not to use generics.

The reason that I do like type checking etc. is that I find in the long run I am more productive. Sure it takes longer to write the initial code but the debugging phase is shorter and overall there is a gain. I have quite a lot of experiance with terse dynamically typed languages, particularly Mathematica and Matlab, and I find that they are good for short, simple, throw away stuff but for something more complex I find I am more productive in Java.

(It could be just that I can type a lot quicker than I can think :) - which if true is sad since I am a two fingered typist)

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Graceful Failure Posted: Aug 24, 2005 8:16 PM
Reply to this message Reply
The reason that I do like type checking etc. is that I find in the long run I am more productive... for something more complex I find I am more productive in Java.

Do you think you would be more productive with languages that provided some minimal local type inference - so you didn't have to explain the type to the compiler in both the declaration and the constructor? (How rude that it doesn't listen the first time you tell it!)

Do you think you would be more productive with languages that provided more static type checking than Java - languages that exclude the possibility of many null pointer references?

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: Graceful Failure Posted: Aug 24, 2005 8:55 PM
Reply to this message Reply
> The reason that I do like type checking etc. is that I
> find in the long run I am more productive... for something
> more complex I find I am more productive in Java.

>
> Do you think you would be more productive with languages
> that provided some minimal local type inference - so you
> didn't have to explain the type to the compiler in both
> the declaration and the constructor? (How rude that it
> doesn't listen the first time you tell it!)

I might be able to type a lot more text and feel more productive, but then I'm going to run the application over and over to find all the runtime bugs.

Limited typing ability/skill might be a motivating factor for some programmers to choose a less verbose language. I've written software for 20 years now. My life experience is that the more characters I type for the compiler the fewer runs before I have a working application.

> Do you think you would be more productive with languages
> that provided more static type checking than Java -
> languages that exclude the possibility of many null
> pointer references?

I can make things work fastest when my confusion over names and types is not sent forth into the runtime environment. Most of my applications are 1000's of lines of code that run for days on end. Finding bugs at runtime is such applications is not feasible. There is just not a way to understand that much code casually. You need a design, a compile time check of your type system, and you need the ability to compartmentalize testing and development.

Than means that you need people to have documentation that is in line with the source code. Printed paper documentation for development is perilously out of date in many cases. Having an interface definition or a class definition to compile against and type check with is powerful at pointing out a very recuring problem, typing mistakes and documentation misreads/misinterpretations.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Graceful Failure Posted: Aug 24, 2005 9:59 PM
Reply to this message Reply
> > The reason that I do like type checking etc. is that
> I
> > find in the long run I am more productive... for
> something
> > more complex I find I am more productive in Java.

> >
> > Do you think you would be more productive with
> languages
> > that provided some minimal local type inference - so
> you
> > didn't have to explain the type to the compiler in both
> > the declaration and the constructor? (How rude that it
> > doesn't listen the first time you tell it!)
>
> I might be able to type a lot more text and feel more
> productive, but then I'm going to run the application over
> and over to find all the runtime bugs.

Gregg, why do you think there would be any more runtime bugs in a language that used local type inference than in Java?


> Limited typing ability/skill might be a motivating factor
> for some programmers to choose a less verbose language.
> I've written software for 20 years now. My life
> e experience is that the more characters I type for the
> compiler the fewer runs before I have a working
> application.

No - telling the compiler the same thing twice achieves nothing.


> > Do you think you would be more productive with
> languages
> > that provided more static type checking than Java -
> > languages that exclude the possibility of many null
> > pointer references?
>
> I can make things work fastest when my confusion over
> names and types is not sent forth into the runtime
> environment. Most of my applications are 1000's of lines
> of code that run for days on end. Finding bugs at runtime
> is such applications is not feasible.

So does that mean you think you'd be more productive with a language that provided more static type checking than Java?

> There is just not a
> way to understand that much code casually. You need a
> design, a compile time check of your type system, and you
> need the ability to compartmentalize testing and
> development.
>
> Than means that you need people to have documentation that
> is in line with the source code. Printed paper
> documentation for development is perilously out of date in
> many cases. Having an interface definition or a class
> definition to compile against and type check with is
> powerful at pointing out a very recuring problem, typing
> mistakes and documentation misreads/misinterpretations.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Graceful Failure Posted: Aug 24, 2005 10:31 PM
Reply to this message Reply
@Isaac Gouy:

> Do you think you would be more productive with languages
> that provided some minimal local type inference - so you
> didn't have to explain the type to the compiler in both
> the declaration and the constructor? (How rude that it
> doesn't listen the first time you tell it!)

I find this difficult to answer, I will explain why:

1. I don't have a lot of experiance with this type of language (some Clean/Haskell experiance)

2. There seems to be pro's and con's; yes there was less typing and it did find the type errors, but the error message were very obscure (like C++ template error messages)

3. Like Gregg Wonderley has pointed out; the typing is probably not the limitation in writting speed, so reducing typing probably has little effect. I would add particularly in a good IDE that does code completion for you.

4. Declaring types adds clarity to a program, its part of the documentation

5. Having sort of knocked implicit typing in the above points I do at times think you could reduce the typing with little or no penalty (see below)

The areas that I think you could reduce typing without much of a hit on clarity, error detection, and error messages are:

A. Make new optional, make {} optional if a body has only one line (like if, for, etc.), make method name and argument types optional if just one method is to be overriden (you still have to leave the brackets though), e.g. instead of:
textField.addActionListner( new ActionListener() {
    public void actionPerformed( ActionEvent notUsed ) {
		textArea.append( textField.getText() );
	}
});

Allow
textField.addActionListner( ActionListener() ( notUsed ) textArea.append( textField.getText() ); );


B. Supress the constructor C++ style when a variable is declared and initialized with a constructor in one line, e.g. instead of StringBuilder message = new StringBuilder() allow StringBuilder message()

In summary: I suspect the gains would be small from implicit typing, but I am in favour of reducing the typing when there is little or no penalty in other areas.

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: Graceful Failure Posted: Aug 25, 2005 5:59 AM
Reply to this message Reply
> > I might be able to type a lot more text and feel more
> > productive, but then I'm going to run the application
> over
> > and over to find all the runtime bugs.
>
> Gregg, why do you think there would be any more runtime
> bugs in a language that used local type inference than in
> Java?

You are going to have to give me a formal description of the inference mechanisms you are talking about, or you are gonna have to tell me which language specifically I am comparing my experiences to.

I make mistakes in what I type. I am a human and thus perfectly capable of making mistakes. I have practicle experience that has shown this to be the case. I've used plenty of dynamic/typeless languages. It is perfectly possible for me to type something that makes it possible to infer typing that has nothing to do with what I intended.

> > Limited typing ability/skill might be a motivating
> factor
> > for some programmers to choose a less verbose language.
> > I've written software for 20 years now. My life
> > e experience is that the more characters I type for the
> > compiler the fewer runs before I have a working
> > application.
>
> No - telling the compiler the same thing twice achieves
> nothing.

Please tell me exactly which 'telling the compiler things twice' you are talking about.

In C++, there is local construction as in

MyType c;

vs

MyType *s = new MyType(...);

In Java, this confusing duality is removed by not providing any automatic construction. In many cases, I have typed

MyType s = new MySubType(...);

which is not redundant at all. The whole point of Java was to remove all Implicit operations that made it possible for the reader and the compiler and the software to be confused about what was intended by the developer.

If that doesn't make sense in your mind, then I am not sure I can type the words here that will help you understand my position on this subject. We are having a semantic communications problem because your compiler is not able to derive the meaning of my text :-) Thus, you are running the wrong program, getting results and incorrectly interpreting them!

> > I can make things work fastest when my confusion over
> > names and types is not sent forth into the runtime
> > environment. Most of my applications are 1000's of
> lines
> > of code that run for days on end. Finding bugs at
> runtime
> > is such applications is not feasible.
>
> So does that mean you think you'd be more productive with
> a language that provided more static type checking
> than Java?

I want to be as explicit as is necessary to remove all chance of any implicit thoughts by a human or action by the runtime being confused with my intent. I don't want to have to 'think' before I type about any implicit behaviors that I am envoking by my programs textual representation. I want to have a small set of explicit actions and activities that I can depend on. Everything else I want to build as program components using the features of the language.

Marcin Kowalczyk

Posts: 40
Nickname: qrczak
Registered: Oct, 2004

Re: Graceful Failure Posted: Aug 26, 2005 2:20 AM
Reply to this message Reply
In Haskell there is no problem with letting the "constructor" taking an explicit comparison function accept any type of elements, and the "constructor" using the implicit default comparison taking only the type which is comparable. Actually the "constructor" is just a global function. Standalone functions are well supported in Haskell. There is no reason to put the constraints on element type in the type definition; they are put in functions which use them.

In most cases it would be more convenient to specify a function which translates the elements to be compared or hashed to a "key" which is then compared using the default comparison for its type, rather than to specify a comparison function directly.

Joe Cheng

Posts: 65
Nickname: jcheng
Registered: Oct, 2002

Re: Graceful Failure Posted: Aug 26, 2005 9:36 AM
Reply to this message Reply
> You are going to have to give me a formal description of
> the inference mechanisms you are talking about, or you are
> gonna have to tell me which language specifically I am
> comparing my experiences to.

Boo is a type inferencing language with otherwise Java-like semantics. http://boo.codehaus.org/Type+Inference

> In Java, this confusing duality is removed by not
> providing any automatic construction. In many cases, I
> have typed
>
> MyType s = new MySubType(...);
>
> which is not redundant at all.

No doubt you have also often typed MyType s = new MyType(...); which is redundant. Anyway the type inferencing languages that I am familiar with always let you be explicit when you need/want to be.

Joe Cheng

Posts: 65
Nickname: jcheng
Registered: Oct, 2002

Re: Graceful Failure Posted: Aug 26, 2005 9:42 AM
Reply to this message Reply
In case the Boo link doesn't make it clear enough what a type inferencing language does, I'll give a quick example.


s = "foo"
s = 1


The second line causes the compile-time error "cannot convert int to string".


s = "foo"
print(s.Length)
i = 10
print(i.Length)


The fourth line causes the compile-time error "'Length' is not a member of int."


o as object = "foo" // be explicit
o = 1


This compiles and runs fine.

Flat View: This topic has 53 replies on 4 pages [ « | 1  2  3  4 | » ]
Topic: The miseducation of C++ programmers Previous Topic   Next Topic Topic: My Pycon 2005 Presentation

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use