Jump to page: 1 24  
Page
Thread overview
Idea: top_cast
Mar 13, 2003
Russ Lewis
Mar 13, 2003
Bill Cox
Mar 13, 2003
Russ Lewis
Mar 13, 2003
Bill Cox
Mar 13, 2003
Sean L. Palmer
Mar 13, 2003
Bill Cox
Mar 14, 2003
Sean L. Palmer
Mar 13, 2003
Russ Lewis
Mar 13, 2003
Bill Cox
Mar 13, 2003
Bill Cox
Mar 14, 2003
Daniel Yokomiso
Mar 14, 2003
Bill Cox
Apr 27, 2003
Walter
Apr 28, 2003
Bill Cox
Apr 30, 2003
Matthew Wilson
Apr 30, 2003
Walter
Apr 27, 2003
Walter
Apr 28, 2003
Bill Cox
Apr 30, 2003
Walter
Mar 14, 2003
Mike Wynn
Mar 14, 2003
Bill Cox
Mar 13, 2003
Russ Lewis
Re: top_cast
Mar 14, 2003
Daniel Yokomiso
Mar 14, 2003
Russ Lewis
Mar 15, 2003
Daniel Yokomiso
Mar 15, 2003
Russ Lewis
Mar 15, 2003
Daniel Yokomiso
Mar 15, 2003
Russ Lewis
Mar 15, 2003
Daniel Yokomiso
Mar 16, 2003
Russ Lewis
Mar 16, 2003
Sean L. Palmer
Mar 16, 2003
Russ Lewis
Mar 17, 2003
Sean L. Palmer
March 13, 2003
Thinking about my previous question, "Double Virtual...", and reading the links about multimethods, I ran across this idea:

top_cast <expr>

This would be a cast operator that, at runtime, discovers the actual (i.e. the top) type of the value, and casts it to that type.  Yes, that means that we are breaking the old C "know all types at compile time" paradigm.  However, there will only be a finite number of possible types that the <expr> could be cast to.  The compiler must attempt to compile code for each one.  However, some may be syntax errors (perhaps you pass the top_cast as a function parameter, but there is not a function implementation that takes all child classes).

The interesting (and difficult) thing about this is that the compiler would have to compile different code paths, one for each possible top type, with an internal switch or lookup table.

So, multimethods would be trivial to implement (from the programmer's
perspective):

class X;
class C1 : X;
class C2 : X;

void foo(C1,C1);
void foo(C1,C2);
void foo(C2,C1);
void foo(C2,C2);

void foo(X a,X b)
{
    try {
        foo(top_cast a, top_cast b);
    }
    catch(Error_top_cast_runtime_syntax_error)
    {
        printf("Oops!  I don't have a foo(...) function for these
types!\n");
    }
}

The function call here tells the compiler to, at runtime (or at compile time, if it can figure out enough stuff), determine what the top class of the variables "X a" and "X b" are.  It then calls the right method based on the type.

I figure that the compiler could throw a Error_top_cast_runtime_syntax_error if it found at runtime a type (or, in this case, set of types) it could not handle.

I expect that there are many other interesting possible uses for top_cast that I haven't considered yet, either...

Thoughts?  Is the programming benefit worth the compiler complexity?
    Russ

--
The Villagers are Online! http://villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


March 13, 2003
Hi, Russ.

This is a nice idea, but IMO, it falls into the category of trying to be too elegant.  The problem with being too elegant, is the next programmer who inherits your code will get lost looking at it.  So, consider:

What's the probability that that new programmer already knows about top_cast?  Not likely.

What's more likely: will he rip it out and rewrite it as the worst possible if-then-else chain, or will he go learn about top_cast, and become a fan?  I wish it were the latter, but most of the time, I see the former.

To protect the code base, I generally discourage use of advanced features whenever the alternative is not more than an ugly page or two of very easy to understand code.

There are those who will argue that reducing the lines of code make it more maintainable, and that forcing use of advanced features will improve my group's overall productivity.  After years of working with groups of programmers in teams, I can tell you that I've found this not to be the case.  Overall productivity is enhanced when you can get everyone to agree on using the same features in the same way.  Doing this is extremely difficult, especially since on avererage programmers leaves after three years on the job.  Keeping the common feature set limited is your best chance of success.

Anyway, it is a cool coding construct.  I wouldn't be upset about it getting into D, but I wouldn't let you use it where I work.

Bill

Russ Lewis wrote:
> Thinking about my previous question, "Double Virtual...", and reading
> the links about multimethods, I ran across this idea:
> 
> top_cast <expr>
> 
> This would be a cast operator that, at runtime, discovers the actual
> (i.e. the top) type of the value, and casts it to that type.  Yes, that
> means that we are breaking the old C "know all types at compile time"
> paradigm.  However, there will only be a finite number of possible types
> that the <expr> could be cast to.  The compiler must attempt to compile
> code for each one.  However, some may be syntax errors (perhaps you pass
> the top_cast as a function parameter, but there is not a function
> implementation that takes all child classes).
> 
> The interesting (and difficult) thing about this is that the compiler
> would have to compile different code paths, one for each possible top
> type, with an internal switch or lookup table.
> 
> So, multimethods would be trivial to implement (from the programmer's
> perspective):
> 
> class X;
> class C1 : X;
> class C2 : X;
> 
> void foo(C1,C1);
> void foo(C1,C2);
> void foo(C2,C1);
> void foo(C2,C2);
> 
> void foo(X a,X b)
> {
>     try {
>         foo(top_cast a, top_cast b);
>     }
>     catch(Error_top_cast_runtime_syntax_error)
>     {
>         printf("Oops!  I don't have a foo(...) function for these
> types!\n");
>     }
> }
> 
> The function call here tells the compiler to, at runtime (or at compile
> time, if it can figure out enough stuff), determine what the top class
> of the variables "X a" and "X b" are.  It then calls the right method
> based on the type.
> 
> I figure that the compiler could throw a
> Error_top_cast_runtime_syntax_error if it found at runtime a type (or,
> in this case, set of types) it could not handle.
> 
> I expect that there are many other interesting possible uses for
> top_cast that I haven't considered yet, either...
> 
> Thoughts?  Is the programming benefit worth the compiler complexity?
>     Russ
> 
> --
> The Villagers are Online! http://villagersonline.com
> 
> .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
> .[ (a version.of(English).(precise.more)) is(possible) ]
> ?[ you want.to(help(develop(it))) ]
> 
> 

March 13, 2003
Some notes about how top_cast would affect function calls:

    obj.foo(obj2);
This is the standard D call.  It is automatically a virtual call, if some
child(ren) override it.

    (top_cast obj).foo(obj2);
This is functionally identical to the one above, since we are determining
the correct method to call by checking the left type at runtime.  (I know, I
know, that's not how vfunction calls are implemented...but that's the
effect.)

    obj.foo(top_cast obj2);
This is a multimethod, but the left side (what will be the "this" pointer)
is of fixed type.  So that means that the argument MUST be of a type for
which obj has an implemented method.  Thus, consider this type family:
    class Arg1;
    class Arg2 : Arg1;
    class Arg3 : Arg2;
    class Obj1
    {
        void foo(Arg1);
        void foo(Arg2);
    }
    void DoStuff(Obj1 obj,Arg1 arg)
    {
        obj.foo(top_cast arg);
    }
In this case, the 'arg' variable could be any of three types:
    Arg1: top_cast simply is a no-op.  This is equivalent to:
        obj.foo(arg);
    Arg2: top_cast casts the object to Arg2.  This is equivalent to:
        obj.foo(cast(Arg2)arg);
    Arg3: top_cast casts the object to Arg3.  However, class Obj doesn't
have an implementation for that, so it gets implicitly downcast back to Arg2
when the function is called:
        obj.foo(cast(Arg3)arg);        // Obj::foo(Arg2) gets called here

If you top_cast both sides, then things are even more complex:
    (top_cast obj).foo(top_cast arg);
In this case, you might have another class:
    class Obj2 : Obj1
    {
        void foo(Arg1);
        void foo(Arg3);
    };
Now the possibilities are like this:
    Obj1,Arg1: both top_casts are no-ops
        obj.foo(arg);
    Obj1,Arg2: left is no-op, cast right to Arg2:
        obj.foo(cast(Arg2)arg);    // Obj1::foo(Arg2) gets called
    Obj1,Arg3: left is no-op, cast right to Arg3, then downcast to Arg2:
        obj.foo(cast(Arg3)arg);    // Obj1::foo(Arg2) gets called
    Obj2,Arg1: cast left to Obj1, right is no-op
        (cast(Obj2)obj).foo(arg);    // Obj2::foo(Arg1) gets called
    Obj2,Arg2: cast left to Obj1, right to Arg2.  Base implementation (in
Obj1) gets called
        (cast(Obj2)obj).foo(cast(Arg2)arg);    // Obj1::foo(Arg2) gets
called
    Obj2,Arg3: cast left to Obj1, right to Arg3.  We DON'T have to downcast,
because Obj2 has an implementation for Arg3
        (cast(Obj2)obj).foo(cast(Arg3)arg);    // Obj2::foo(Arg3) gets
called
So, you see that top_cast'ing the left side gives us access not only to
virtual functions, but also to new functions only defined further down the
type tree.

You may also notice that, in this case, we can simplify things somewhat.  If 'arg' is either Arg1 or Arg2, then we can just use D's existing virtual function call implementation.  The compiler would produce code something like this:

    // implementing '(top_cast obj).foo(top_cast arg);'
    switch(arg.classinfo)
    {
    case Arg1:
        obj.foo(arg);    // use the virtual function foo(Arg1)
        break;
    case Arg2:
        obj.foo(cast(Arg2)arg);    // use the virtual function foo(Arg2)
        break;
    case Arg3:
        if(obj.classinfo == Obj1)
            obj.foo(cast(Arg2)arg);
        else
            (cast(Obj2)obj).foo(cast(Arg3)arg);
        break;
    }

--
The Villagers are Online! http://villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


March 13, 2003
Bill Cox wrote:

> Anyway, it is a cool coding construct.  I wouldn't be upset about it getting into D, but I wouldn't let you use it where I work.

A reasonable position.  Hopefully, in time, its use would become widespread enough that you'd allow it into your shop!

People probably said the exact same thing about virtual functions when they first came out, and they were probably correct then too.

--
The Villagers are Online! http://villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


March 13, 2003
Hi, Russ.

Russ Lewis wrote:
> Bill Cox wrote:
> 
> 
>>Anyway, it is a cool coding construct.  I wouldn't be upset about it
>>getting into D, but I wouldn't let you use it where I work.
> 
> 
> A reasonable position.  Hopefully, in time, its use would become widespread
> enough that you'd allow it into your shop!
> 
> People probably said the exact same thing about virtual functions when they
> first came out, and they were probably correct then too.
> 
> --
> The Villagers are Online! http://villagersonline.com
> 
> .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
> .[ (a version.of(English).(precise.more)) is(possible) ]
> ?[ you want.to(help(develop(it))) ]

If programmers were generally familiar with the construct, I'd support it's use.  Virtual functions are an interesting example.  I'd guess that almost half of the C++ GUI programmers I've worked with don't really know what it does.  Since they generally just inherit from a base GUI class, and overide functions, they never have to decide when to make a function virtual or not.  When put into that position, I've seen GUI programmers opt for simply making everything virtual, rather than learning what virtual really means.  I love that virtual is gone in Java, and that the compiler is responsible for figuring it out.

I've got some funny stories about what programmers did when they inherited really good code that they couldn't understand, but most are only funny if you know EDA really well.  However, I've heard a good one that came up in one of the oldest visual editors: vi.

The original author's of vi discovered that searching for strings can be done in time proportional to the size of the file, rather than the worst case (and not typical) case of having to compare most of the characters in a string to most of the characters in a file.  It's a complex algorithm involving "failure functions" that tell you what state to go to when a mismatched character is encountered.  These guys wrote all this great code, and demonstraited the world's fastest text search in history.

The next programmer who inherited vi had no clue what all that code was about.  He replaced it with strcmp vs every character in the file!

Bill

March 13, 2003
Here's an idea:  Don't hire programmers that suck, or don't give them unlimited freedom to fuck up perfectly working code elsewhere in the codebase just because they "don't understand it".  Don't pull all the good programmers down just because there are bad programmers out there.

Sean

"Bill Cox" <bill@viasic.com> wrote in message news:3E70AFCD.9040308@viasic.com...
> If programmers were generally familiar with the construct, I'd support it's use.  Virtual functions are an interesting example.  I'd guess that almost half of the C++ GUI programmers I've worked with don't really know what it does.  Since they generally just inherit from a base GUI class, and overide functions, they never have to decide when to make a function virtual or not.  When put into that position, I've seen GUI programmers opt for simply making everything virtual, rather than learning what virtual really means.  I love that virtual is gone in Java, and that the compiler is responsible for figuring it out.
>
> I've got some funny stories about what programmers did when they inherited really good code that they couldn't understand, but most are only funny if you know EDA really well.  However, I've heard a good one that came up in one of the oldest visual editors: vi.
>
> The original author's of vi discovered that searching for strings can be done in time proportional to the size of the file, rather than the worst case (and not typical) case of having to compare most of the characters in a string to most of the characters in a file.  It's a complex algorithm involving "failure functions" that tell you what state to go to when a mismatched character is encountered.  These guys wrote all this great code, and demonstraited the world's fastest text search in history.
>
> The next programmer who inherited vi had no clue what all that code was about.  He replaced it with strcmp vs every character in the file!
>
> Bill


March 13, 2003
Hi, Sean.

Sean L. Palmer wrote:
> Here's an idea:  Don't hire programmers that suck, or don't give them
> unlimited freedom to fuck up perfectly working code elsewhere in the
> codebase just because they "don't understand it".  Don't pull all the good
> programmers down just because there are bad programmers out there.
> 
> Sean

What make a programmer a good programmer?  I'd say a good GUI programmer cranks out good GUIs fast.  A good Perl hacker generates HTML pages 10 times faster than most of the rest of us.  Good GUI programmers often don't understand how to write templates, never used unions, and really don't create very complex data structures.  Most Perl programmers don't use any of the high-level capabilities of Perl.

I'd hire both of them.

Bill

March 13, 2003
Ouch, Sean.  That was uncalled for.  I understand your sentiment, but that was vicious.

"Sean L. Palmer" wrote:

> Here's an idea:  Don't hire programmers that suck, or don't give them unlimited freedom to fuck up perfectly working code elsewhere in the codebase just because they "don't understand it".  Don't pull all the good programmers down just because there are bad programmers out there.

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


March 13, 2003
Hi, again.  Just a few more random thoughts about hiring only good programmers...

Sean L. Palmer wrote:
> Here's an idea:  Don't hire programmers that suck, or don't give them
> unlimited freedom to fuck up perfectly working code elsewhere in the
> codebase just because they "don't understand it".  Don't pull all the good
> programmers down just because there are bad programmers out there.
> 
> Sean

I agree about keeping programmers who can mess up code away from the code.  I don't let our GUI guys hack our algorithms, and vise-versa. The main problem, though, isn't stupid programmers, it's inexperienced programmers.

I look back at code I wrote a long time ago, and frankly, it stinks. Experience really does count, at least the first few years.  We hire mostly out of school, and always have a lot of training to do.  I'd say we succeed in hiring very bright people, and that it pays off to do so, even if we have to train them.  However, we have to help them get through that phase when their code still stinks.

Naturally, every bright programmer we hire wants to jump right in and work on the most sensitive code.  It's hard to hold them back to simpler, well contained pieces of the system while they're still learning.  A lot of the problems arise when I relent, and put a guy into a situation he's not quite ready for.  A lot of the problems are therefore really my fault.

However, there's another nasty condition that I run into.  The smarter a guy is, the more he hates reading other peoples code.  They practically look for excuses to rewrite it (BTW, I do let them rewrite tons of code... old code can be a liability).  This results in good code being deleted and re-written badly pretty often.  Also, when a smart guy gets an idea, it's often really hard to change it, even when he's wrong.  I'd say posts on this group support this assertion.  I'm not goint to claim to be an exception.

Here's a receient example at work.  I hired a brilliant guy out of Duke, and have been training him for two years.  He's scary smart.  For example, there were several years where he never got a math problem wrong on any test, including SAT, SAT2, AP tests, and several high-school and college classes.  I've found that these kinds of guys make great algorithms developers, and he's worked out well overall.

He hates the fact that we have duplicated a very complex function in the routing database in two different places.  It's morally offensive to him.  The same code is literally repeated, but with minor changes.  The first version computes the shape of a wire from the routing data structures.  The second computes what shape would result if we built the routing data structures, but does it without building them.  The direct computation from the data structures is the most inner-loop code in our system.  The what-if code runs several times slower.

I updated my source code a couple weeks ago, and all my stuff ran much slower.  I wasted half the day to find that he'd deleted (not commented out) the fast direct computation, and emulated it's functionality by calling the what-if version.  I had to check out an old version and undo his hack, but I also added a capability so that in debug mode, the what-if version is called, and the results are compared to the normal version.  We still have two similar copies of code, but at least we know they are in sync.

I updated again a couple of days ago, and the slow behavior came back. It turns out he'd commented out the if-statement around the check, so that it was always called.  Of course, I had to put it back the way it was, so our tools would run at a competitive speed, and so I could get my work done in reasonable time.  I bet that the slow behavior will be back next time I update.

What do you do?  The smartest programmers are often the ones causing the most problems.  I can't fire them.  They're too productive.  In fact, they know it, and do all kinds of crap just to piss you off!  It's just part of living in the real world.  And besides, I deserve it.  My old bosses tell horror stories about having to manage me.

Bill

March 13, 2003
Hey, it's no problem.  I understand the sentiment.

I advocate putting in hand-rails in langauges for the less-than-average programmers, like removing pointers and making everything virtual and letting the compiler fix it.  I also encourage programmers to write their programs as if the target audience is stupid people.  That point of view gets a strong reaction from many.  It's certainly not what super-smart people who enjoy very advanced language features want to hear.

Bill

Russ Lewis wrote:
> Ouch, Sean.  That was uncalled for.  I understand your sentiment, but that was
> vicious.
> 
> "Sean L. Palmer" wrote:
> 
> 
>>Here's an idea:  Don't hire programmers that suck, or don't give them
>>unlimited freedom to fuck up perfectly working code elsewhere in the
>>codebase just because they "don't understand it".  Don't pull all the good
>>programmers down just because there are bad programmers out there.
> 
> 
> --
> The Villagers are Online! villagersonline.com
> 
> .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
> .[ (a version.of(English).(precise.more)) is(possible) ]
> ?[ you want.to(help(develop(it))) ]
> 
> 

« First   ‹ Prev
1 2 3 4