www.digitalmars.com         C & C++   DMDScript  

D - Idea: top_cast

reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
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))) ]
Mar 13 2003
next sibling parent reply Bill Cox <bill viasic.com> writes:
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))) ]
 
 

Mar 13 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
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))) ]
Mar 13 2003
parent reply Bill Cox <bill viasic.com> writes:
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
Mar 13 2003
parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
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

Mar 13 2003
next sibling parent reply Bill Cox <bill viasic.com> writes:
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
Mar 13 2003
parent "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
If you're trying to make a run-of-the-mill program, hire a run-of-the-mill
programmer.  If you need something exotic, adding more lines of code won't
necessarily get the problem solved.

I see your point.  If you don't need a guru, stay away from them;  they'll
"upgrade" your codebase until mere mortals can't understand it.

Sean

"Bill Cox" <bill viasic.com> wrote in message
news:3E70E906.1000408 viasic.com...
 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


 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

Mar 13 2003
prev sibling next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
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))) ]
Mar 13 2003
parent Bill Cox <bill viasic.com> writes:
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))) ]

Mar 13 2003
prev sibling next sibling parent reply Bill Cox <bill viasic.com> writes:
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
Mar 13 2003
next sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Bill Cox" <bill viasic.com> escreveu na mensagem
news:3E70F283.1070301 viasic.com...
 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


 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

Here's my two cents. Since I started studying project management (and working as a consultant in these techniques) there's one thing about teams that I never ignore. You have to be able to trust in your team. If they lie to you, they work behind the scenes, they have their own agenda or if they have no concept of responsibility, things will just get worse over time. Good programmers can write efficient and well-designed software, not only one of these. It's a matter of time for a bad programmer to mess with an entire project. You can define some rules, like minimum performance, and write automated tests to check this. Run these tests every other hour, before every build, whenever you'll think it's important, and treat their failures as bugs. Make these programmers know that if performance goes down it's a bug and they should never put bugs in. At least you'll be able to verify when things get wrong. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.461 / Virus Database: 260 - Release Date: 10/3/2003
Mar 14 2003
parent reply Bill Cox <bill viasic.com> writes:
 Here's my two cents. Since I started studying project management (and
 working as a consultant in these techniques) there's one thing about teams
 that I never ignore. You have to be able to trust in your team.

I agree. I may have given the impression that I manage my teams. That's not exactly right. I fill a lead technical roll, and try to get a good manager involved to run the group. It's a tag-team aproach that I've found extremely effective. There are huge benifits in having the group's technical lead/mentor not be everyone's boss. I haven't studied management techniques at all, but I've found it odd that this tag-team aproach isn't more wide spread. Usually, companies promote the best tech guy, often losing a great asset while creating a monster. Bill
Mar 14 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3E71DDC7.1090904 viasic.com...
 I agree.  I may have given the impression that I manage my teams.
 That's not exactly right.  I fill a lead technical roll, and try to get
 a good manager involved to run the group.  It's a tag-team aproach that
 I've found extremely effective.  There are huge benifits in having the
 group's technical lead/mentor not be everyone's boss.

 I haven't studied management techniques at all, but I've found it odd
 that this tag-team aproach isn't more wide spread.  Usually, companies
 promote the best tech guy, often losing a great asset while creating a
 monster.

You're right. Management and technical expertise rarely reside in the same person. In more successful projects I've been involved with teams on, I've done the technical lead while someone *else* does the managing.
Apr 26 2003
parent reply Bill Cox <bill viasic.com> writes:
Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E71DDC7.1090904 viasic.com...
 
I agree.  I may have given the impression that I manage my teams.
That's not exactly right.  I fill a lead technical roll, and try to get
a good manager involved to run the group.  It's a tag-team aproach that
I've found extremely effective.  There are huge benifits in having the
group's technical lead/mentor not be everyone's boss.

I haven't studied management techniques at all, but I've found it odd
that this tag-team aproach isn't more wide spread.  Usually, companies
promote the best tech guy, often losing a great asset while creating a
monster.

You're right. Management and technical expertise rarely reside in the same person. In more successful projects I've been involved with teams on, I've done the technical lead while someone *else* does the managing.

One trick is to find a good manager who will let the tech-guys lead. Even if the manager is a superior programmer, I find that the guys doing the actual work usually come up with better solutions. You have to be able to turn off your technical insights, and let the creativity come from your workers. The best team I ever worked with was QuickLogic in the early 90's, where we didn't really have a manager. One of the founders was in charge of our group, and he's a great guy. However, he had no interest in real management, so far as I can tell. He just worked on his own stuff and let us do our stuff. In a vacuum of direction for the group, we had to define our own goals, and then we work together to meet them. The results were amazing. I wish I could reproduce it. After seeing our early success, QuickLogic naturally promoted our best tech guy and mentor to run the group, and that turned out to be a disaster. He had some bad physical problems, but I bet failing at management contributed to his suicide within about a year. Since then, I've worked hard to stay out of management, and it's been a good thing so far. Bill P.S. If old stories aren't apropriate for this group, let me know, and I'll stop posting them. I hope they're enjoyable rather than annoying.
Apr 28 2003
next sibling parent "Matthew Wilson" <matthew stlsoft.org> writes:
 P.S.  If old stories aren't apropriate for this group, let me know, and
 I'll stop posting them.  I hope they're enjoyable rather than annoying.

Occasionally instructive. Always worth a read. They're fine by me.
Apr 30 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3EAD05C1.3090300 viasic.com...
 P.S.  If old stories aren't apropriate for this group, let me know, and
 I'll stop posting them.  I hope they're enjoyable rather than annoying.

Oh, I think they're a great read. Please keep posting! P.S. I've done my best to avoid the management track.
Apr 30 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3E70F283.1070301 viasic.com...
 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.

Code can benefit enormously from being rewritten, *provided* it is being rewritten by the same guy who wrote it in the first place. Otherwise, the new guy doesn't understand what all the undocumented cruft in the old code does, ignores it in the rewrite, and so repeats every bug the cruft was added to fix.
Apr 26 2003
parent reply Bill Cox <bill viasic.com> writes:
Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E70F283.1070301 viasic.com...
 
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.

Code can benefit enormously from being rewritten, *provided* it is being rewritten by the same guy who wrote it in the first place. Otherwise, the new guy doesn't understand what all the undocumented cruft in the old code does, ignores it in the rewrite, and so repeats every bug the cruft was added to fix.

Yep. As I'm sure you remember, it's nice to be in EDA in these cases. With a thousand or so test cases from customers, you can check for every obscure bug that you've had to fix in the past, and verify performance. I imagine that writing compilers is possibly like that. I try not to let new code replace the old code until the new code does a better job, and passes all the tests. I find most programmers ignore the old code until this stage, and then poor over it carefully looking for nuggets of wisdom. It can be pretty hard beating a 4 year old tool without reading it to see what it does. Of course, if a programmer's not a team player, there's not much you can do. We just lost the programmer I described as the super-smart guy that I was having some trouble working with. Replacing fast code with slow code was something he did all the time. It was his method of debugging. If he traced a problem into your code, rather than fixing it, he'd rewrite it in the simplest way possible, which usually was very slow. A number of times, the tool just slowed down to a crawl, and I spent a day tracing the problem to one of his fixes. Also, the tool got somewhat slower every day. I've had to abondon the entire code base he was involved with even though I wrote half of it, and I'm working lots of overtime rewriting it now. Bill
Apr 28 2003
parent "Walter" <walter digitalmars.com> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3EACFD6C.8000400 viasic.com...
 Yep.  As I'm sure you remember, it's nice to be in EDA in these cases.
 With a thousand or so test cases from customers, you can check for every
 obscure bug that you've had to fix in the past, and verify performance.
   I imagine that writing compilers is possibly like that.

Very much so. My test suite is mainly a distillation of 20 years of bug reports <g>.
 I try not to let new code replace the old code until the new code does a
 better job, and passes all the tests.  I find most programmers ignore
 the old code until this stage, and then poor over it carefully looking
 for nuggets of wisdom.  It can be pretty hard beating a 4 year old tool
 without reading it to see what it does.

Frequently, those nuggets consist of "if running under operating system XX.YY, work around this weird OS bug by doing this kludge". Developing under the latest OS means the new programmers will not see the problem until it's too late.
 Of course, if a programmer's not a team player, there's not much you can
 do.  We just lost the programmer I described as the super-smart guy that
 I was having some trouble working with.  Replacing fast code with slow
 code was something he did all the time.  It was his method of debugging.
   If he traced a problem into your code, rather than fixing it, he'd
 rewrite it in the simplest way possible, which usually was very slow.  A
 number of times, the tool just slowed down to a crawl, and I spent a day
 tracing the problem to one of his fixes.  Also, the tool got somewhat
 slower every day.  I've had to abondon the entire code base he was
 involved with even though I wrote half of it, and I'm working lots of
 overtime rewriting it now.

He doesn't sound that smart to me <g>.
Apr 30 2003
prev sibling parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
news:b4qkd6$12ms$1 digitaldaemon.com...
 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.

out the junk and wrote a smart lazy evaluating fast version of some code, the manager then removed it all because he did not understand how it could work! turned out the manager wrote version 1 and was upset that some contractor could write in 1 month a perfectly working version of something the manager has spent a year bodging and bugfixing. a good programmer is one who learns, and accepts there's always someone who can do (or has done) whatever better than they can (could). imho the best programmer is one how help the guy who can write a better version the code to do exactly that. but I'm baised, I know I'm a shite programmer, but I still think " 'cos it is " is the worst reason for never explaining why something was implemented in a particular way and I'm lazy, why write something someone else has written and tested for you. (if it turns out it don't work you can blaim someone else and head off to the pub for the rest of the day.) its bad project managment/leadership if someone who does not know what or why they are doing something is let loose on a section of code. didn't some bloke 2000 years ago write "before you unwind the for loop in your brothers code take the unbounded recursion out of your own."
Mar 13 2003
parent Bill Cox <bill viasic.com> writes:
Mike Wynn wrote:
 "Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
 news:b4qkd6$12ms$1 digitaldaemon.com...
 
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.

its not always the programmers, have a friend who did the oposite, striped out the junk and wrote a smart lazy evaluating fast version of some code, the manager then removed it all because he did not understand how it could work! turned out the manager wrote version 1 and was upset that some contractor could write in 1 month a perfectly working version of something the manager has spent a year bodging and bugfixing Just another story along these lines...

At QuickLogic, I read a paper called RICE, which was a fun mathematical way to quickly predict net delays in circuits. I wrote a prototype over the weekend, and demonstrated it Monday. The code worked great. It dramatically improved our timing estimates, giving good estimates 99.99% of the time (the other .01% had to be done with the old techniques). My boss at the time was my EDA mentor, a truly brilliant guy and outstanding programmer, but with no background in math. He couldn't understand how my code worked, so he simply refused to believe it. He wouldn't let me put it in the tools until he had it validated. He hired Professor Pillage to come examine my work. Professor Pillage was the author of the RICE paper. It turns out that RICE failed to get a good answer 10% of the time, not 0.01% like my version. I showed him how to fix RICE. Then, he went around to all the EDA companies, and showed them how to do it! It remains the standard aproach today. BTW, back around 1994, I upgraded QuickLogic's timing estimation to a better method, which makes AWE obsolete for net delay estimation. I tried to publish it, but the academics wouldn't accept it without a professor behind it! If you're interested, I've got a weak patent on the topic that explains how to do it, and is easy to work around: 5,675,502. Bill
Mar 14 2003
prev sibling next sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
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))) ]
Mar 13 2003
prev sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> escreveu na mensagem
news:3E70A041.E91A9210 deming-os.org...
 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))) ]

This only works if there is always a most specialized method. But sometimes it's not the case: class A; class B : A; class C : A; class D : B; void foo(A a, A 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"); } } foo(B,A) foo(A,C) foo(B,C) foo(D,A) What should we do when we call "foo(someD, someC)"? This problem can get worse with interfaces. This solution would be good just for some cases. I'm a big fan of multimethods, but they need language support to get right and safe. With this syntax there's also problems with return types: a method return void, another return int and other return Foo. But such feature could be defined as a library function, it just needs reflection to get right. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.461 / Virus Database: 260 - Release Date: 10/3/2003
Mar 13 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Daniel Yokomiso wrote:

 This only works if there is always a most specialized method. But sometimes
 it's not the case:

 class A;
 class B : A;
 class C : A;
 class D : B;

 void foo(A a, A 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");
     }
 }

 foo(B,A)
 foo(A,C)
 foo(B,C)
 foo(D,A)

 What should we do when we call "foo(someD, someC)"? This problem can get
 worse with interfaces. This solution would be good just for some cases. I'm
 a big fan of multimethods, but they need language support to get right and
 safe. With this syntax there's also problems with return types: a method
 return void, another return int and other return Foo. But such feature could
 be defined as a library function, it just needs reflection to get right.

The runtime algorithm would be as follows: 1) Cast all top_cast expressions to their current (top) type. This is NOT ambiguous, since each reference points to a single object, and all objects have a single type, even though you have many possible pointers. 2) Evaluate the expression as though the programmer had manually cast these expressions to these types. Likewise, this is NOT ambiguous, because D has resolution rules. 3) If there is no legal way to evaluate the runtime type combination, then throw Error_top_cast_runtime_syntax_error Please, though, restate your example. I didn't understand it entirely. What overloaded versions of foo() are available? Also note that your example can potentially do infinite recursion if foo(A,A) calls itself because the objects are both literal A objects (or if that is the best implementation for the combination of objects that you pass it). -- 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))) ]
Mar 14 2003
parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> escreveu na mensagem
news:3E71DB70.485FEC81 deming-os.org...
 Daniel Yokomiso wrote:

 This only works if there is always a most specialized method. But


 it's not the case:

 class A;
 class B : A;
 class C : A;
 class D : B;

 void foo(A a, A 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");
     }
 }

 foo(B,A)
 foo(A,C)
 foo(B,C)
 foo(D,A)

 What should we do when we call "foo(someD, someC)"? This problem can get
 worse with interfaces. This solution would be good just for some cases.


 a big fan of multimethods, but they need language support to get right


 safe. With this syntax there's also problems with return types: a method
 return void, another return int and other return Foo. But such feature


 be defined as a library function, it just needs reflection to get right.

The runtime algorithm would be as follows: 1) Cast all top_cast expressions to their current (top) type. This is NOT ambiguous, since each reference points to a single object, and all objects

 a single type, even though you have many possible pointers.
 2) Evaluate the expression as though the programmer had manually cast

 expressions to these types.  Likewise, this is NOT ambiguous, because D

 resolution rules.
 3) If there is no legal way to evaluate the runtime type combination, then

 Error_top_cast_runtime_syntax_error

 Please, though, restate your example.  I didn't understand it entirely.

 overloaded versions of foo() are available?

 Also note that your example can potentially do infinite recursion if

 calls itself because the objects are both literal A objects (or if that is

 best implementation for the combination of objects that you pass it).

 --
 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))) ]

This is a simple program tested with dmd 0.59. class A { } class B : A { } class C : A { } class D : B { } void foo(A a1, A a2) { printf("foo(A,A)\r\n"); } void foo(B b, A a) { printf("foo(B,A)\r\n"); } void foo(A a, C c) { printf("foo(A,C)\r\n"); } void foo(B b, C c) { printf("foo(B,C)\r\n"); } void foo(D d, A a) { printf("foo(D,A)\r\n"); } 1int main() { A a = new A(); B b = new B(); C c = new C(); D d = new D(); foo(a, a); // foo(A,A) foo(a, b); // foo(A,A) foo(a, c); // foo(A,C) foo(a, d); // foo(A,A) foo(b, a); // foo(B,A) // function foo overloads void(A a1,A a2) and void(B b,A a) both match argument list for foo // foo(b, b); foo(b, c); // foo(B,C) // function foo overloads void(A a1,A a2) and void(B b,A a) both match argument list for foo // foo(b, d); foo(c, a); // foo(A,A) foo(c, b); // foo(A,A) // function foo overloads void(A a1,A a2) and void(A a,C c) both match argument list for foo // foo(c, c); foo(c, d); // foo(A,A) foo(d, a); // foo(D,A) // function foo overloads void(A a1,A a2) and void(D d,A a) both match argument list for foo // foo(d, b); // function foo overloads void(A a1,A a2) and void(D d,A a) both match argument list for foo // foo(d, c); // function foo overloads void(A a1,A a2) and void(D d,A a) both match argument list for foo // foo(d, d); return 0; } It's difficult to define what is the most specialized version of the method. There's a long list of discussions about it in Usenet. I participated in some discussions in comp.lang.eiffel. There's also a problem if you define a function overloaded for interfaces: interface I { } interface J { } void foo(I i, J j) { printf("foo(I,J)\r\n"); } void foo(J j, I i) { printf("foo(J,I)\r\n"); } class A : I { } class B : J { } class C : I, J { } int main() { A a = new A(); B b = new B(); C c = new C(); I i = a; J j = b; I ic = c; J jc = c; foo(a, b); // foo(I,J) foo(b, a); // foo(J,I) foo(a, c); // foo(I,J) foo(b, c); // foo(J,I) // function foo overloads void(I i,J j) and void(J j,I i) both match argument list for foo // foo(c, c); foo(c, a); // foo(J,I) foo(c, b); // foo(I,J) foo(i, j); // foo(I,J) foo(j, i); // foo(J,I) foo(i, jc); // foo(I,J) foo(ic, j); // foo(I,J) return 0; } I can write more examples showing how different combinations of method definitions and calls can be resolved in a static context, but may fail in runtime, while some other combinations could work in a runtime context, but fail in static time. If you add OO polymorphism things get worse, because any possible descendent can write additional methods that'll cause ambiguity at runtime. To provide multi-dispatch we need compiler support to invalidate ambiguous cases and force the programmer to disambiguate them (by adding more function versions). --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.461 / Virus Database: 260 - Release Date: 10/3/2003
Mar 14 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Daniel Yokomiso wrote:

 It's difficult to define what is the most specialized version of the
 method. There's a long list of discussions about it in Usenet. I
 participated in some discussions in comp.lang.eiffel. There's also a problem
 if you define a function overloaded for interfaces:

Fair enough. But the problem is already confronted in D, as you point out. The issue is orthogonal to top_cast. -- 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))) ]
Mar 14 2003
parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> escreveu na mensagem
news:3E72D829.67D10122 deming-os.org...
 Daniel Yokomiso wrote:

 It's difficult to define what is the most specialized version of the
 method. There's a long list of discussions about it in Usenet. I
 participated in some discussions in comp.lang.eiffel. There's also a


 if you define a function overloaded for interfaces:

Fair enough. But the problem is already confronted in D, as you point

 issue is orthogonal to top_cast.

 --
 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))) ]

Such feature (top_cast) needs specialized support to work correctly or it can introduce weird bugs in your application. In cases like this (double-dispatch) the standard OO solution is a visitor or something similar. There's a nice link at wiki, with lots of discussion on the related pages. http://c2.com/cgi/wiki?DoubleDispatchExample In D we can have a multidispatch solution using delegates, as in Burton's post. These two solutions are safe and easy to predict. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.462 / Virus Database: 261 - Release Date: 13/3/2003
Mar 15 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Daniel Yokomiso wrote:

 Such feature (top_cast) needs specialized support to work correctly or it
 can introduce weird bugs in your application. In cases like this
 (double-dispatch) the standard OO solution is a visitor or something
 similar. There's a nice link at wiki, with lots of discussion on the related
 pages.

I don't understand how it can cause bugs, more than manual casting would. Can you give details? If I am missing something, I honestly and earnestly would like to see it!
 In D we can have a multidispatch solution using delegates, as in Burton's
 post. These two solutions are safe and easy to predict.

I've looked at delegates, but they don't work to replace top_cast because they are fpointer-with-obj, not fpointer-into-class. That is, you'd need a different delegate for every right-hand object, instead of for every right-hand object class. -- 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))) ]
Mar 15 2003
parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> escreveu na mensagem
news:3E737084.28AADA97 deming-os.org...
 Daniel Yokomiso wrote:

 Such feature (top_cast) needs specialized support to work correctly or


 can introduce weird bugs in your application. In cases like this
 (double-dispatch) the standard OO solution is a visitor or something
 similar. There's a nice link at wiki, with lots of discussion on the


 pages.

I don't understand how it can cause bugs, more than manual casting would.

 you give details?  If I am missing something, I honestly and earnestly

 like to see it!

Some unambiguous method call involving "top_cast" and a set of classes S could work correctly, because all possibilities used are tested and correctly defined. But some days/months/years later a programmer introduces a new class into your framework that breaks the fragile existing stability. Or he can define a new overloaded function that will cause problems with some weird combination of classes. It's like manual casting plus function pointers to simulate OO in C. Let me dig some strange cases (Eiffel syntax here, sorry guys :-) ): class A end class B inherit A end class C inherit A end class D inherit B end class E inherit C, D end class G a_method(a:A):A is do end a_method(b:B):B is do end a_method(c:C):C is do end a_method(d:D):D is do end a_method(e:E):E is do end end The previous classes respects all my overloading rules. But if you, or anyone else, add later the following class: class F inherit B and C end It should be always valid. And then someone could make: local a:A b:B c:C f:F g:G create f create g a := f b := f c := f a := g.a_method(a) -- doesn´t matter the method call here, any result conforms to A b := g.a_method(b) -- if you select in runtime a_method(C):C you can get a problem c := g.a_method(c) -- if you select in runtime a_method(B):B you can get a problem Note that doesn't matter if they're classes or interfaces. In Eiffel everything is a class, but in D with interfaces the same kind of problems can happen. Some cases may not happen in your tests, it's almost impossible to write comprehensive tests.
 In D we can have a multidispatch solution using delegates, as in


 post. These two solutions are safe and easy to predict.

I've looked at delegates, but they don't work to replace top_cast because

 are fpointer-with-obj, not fpointer-into-class.  That is, you'd need a

 delegate for every right-hand object, instead of for every right-hand

 class.

It works by forcing each subclass to register itself in a registry controlling method versions. Something like this (it's different from Burton's post): module shapes; // some kind of storage is necessary, like hashes of hashes. Method getMethodFor(ClassInfo shapeA, ClassInfo shapeB); void registerMethodFor(ClassInfo shapeA, ClassInfo shapeB, Method method); module shape; import shapes; static this() { registerMethodFor(Shape.class, Shape.class, method1); registerMethodFor(Square.class, Triangle.class, method2); registerMethodFor(Circle.class, Triangle.class, method3); registerMethodFor(Square.class, Circle.class, method4); } void method1(Shape a, Shape b) { printf("method1(Shape a, Shape b)\r\n"); } void method2(Square a, Triangle b) { printf("method2(Square a, Triangle b)\r\n"); } void method3(Circle a, Triangle b) { printf("method3(Circle a, Triangle b)\r\n"); } void method4(Square a, Circle b) { printf("method4(Square a, Circle b)\r\n"); } class Shape { void method(Shape other) { getMethodFor(this.classInfo(), other.classInfo()).invoke(this, other); } } Search for efficient multi-dispatch in CiteSeer and you'll get some good hints of ways to do this in a performance-wise way.
 --
 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))) ]

--- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.462 / Virus Database: 261 - Release Date: 13/3/2003
Mar 15 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Daniel Yokomiso wrote:

 Some unambiguous method call involving "top_cast" and a set of classes S
 could work correctly, because all possibilities used are tested and
 correctly defined. But some days/months/years later a programmer introduces
 a new class into your framework that breaks the fragile existing stability.
 Or he can define a new overloaded function that will cause problems with
 some weird combination of classes. It's like manual casting plus function
 pointers to simulate OO in C. Let me dig some strange cases (Eiffel syntax
 here, sorry guys :-) ):

A similar argument could be made for virtual functions, couldn't it? A programmer that extends your class library could overload a function in the wrong way, and totally screw things up. top_cast doesn't affect your legacy code when the legacy code is using legacy objects. So adding a new class to the heirarchy can't break old paths. However, top_cast allows your legacy code to interact with new objects. If you so desire, you can use top_cast to allow extensions to your library to add new code paths into the heart of the old library. In places where that is not the design goal, don't use top_cast and you won't get the problem.
 (snip code example)

The example, as I understood it, was a good explanation of how implicit casts to overloaded functions can be fraught with danger, particularly when you have multiple inheritance. How does top_cast make this worse?
 In D we can have a multidispatch solution using delegates, as in


 post. These two solutions are safe and easy to predict.

I've looked at delegates, but they don't work to replace top_cast because

 are fpointer-with-obj, not fpointer-into-class.  That is, you'd need a

 delegate for every right-hand object, instead of for every right-hand

 class.

It works by forcing each subclass to register itself in a registry controlling method versions. Something like this (it's different from Burton's post): module shapes; // some kind of storage is necessary, like hashes of hashes. Method getMethodFor(ClassInfo shapeA, ClassInfo shapeB); void registerMethodFor(ClassInfo shapeA, ClassInfo shapeB, Method method);

Right, this is exactly what I'm implementing currently. I think it's ugly, though. Walter, you've expressed before that you like general purpose features that add to the expressivity of the language in a widely-applicable way, yet don't duplicate other, existing features (not too much, at least). It seems to me that top_cast gives a valuable capability that no existing language feature gives. It is useful for implemeting multimethods, but also (I expect) for other purposes we haven't seen yet. Any thoughts about whether it should make it into the language? In v2, perhaps? -- 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))) ]
Mar 15 2003
parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
That seems like a really bad design philosophy, because the nature of the
language becomes entirely dependent on the order in which you added the
features.  If you don't think of the cool features til last, the whole
language will look like a frankenstein monster.

Any time you add a feature you need to refactor the existing features.  If
there is going to be one way of doing things it should be the best way, not
the first way added.

Sean

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3E741FDF.9F12D35C deming-os.org...
 Walter, you've expressed before that you like general purpose features

 to the expressivity of the language in a widely-applicable way, yet don't
 duplicate other, existing features (not too much, at least).  It seems to

 that top_cast gives a valuable capability that no existing language

 gives.  It is useful for implemeting multimethods, but also (I expect) for

 purposes we haven't seen yet.  Any thoughts about whether it should make

 the language?  In v2, perhaps?

Mar 16 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
"Sean L. Palmer" wrote:

 That seems like a really bad design philosophy, because the nature of the
 language becomes entirely dependent on the order in which you added the
 features.  If you don't think of the cool features til last, the whole
 language will look like a frankenstein monster.

 Any time you add a feature you need to refactor the existing features.  If
 there is going to be one way of doing things it should be the best way, not
 the first way added.

I agree, and I don't think that that was Walter's strategy. I was attempting to recognize that one of Walter's key concerns is with orthogonality - he wants new features to add new expressive dimensions to the language, not just be syntax sugar for old ones. IMHO, top_cast is one of those features. -- 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))) ]
Mar 16 2003
parent "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
I agree with that.

So far Walter's additions have been very clearly adding new features.

Sorry I have such a negative attitude lately.  I don't know what's come over
me.  ;(

Sean

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3E74ED0E.6D846B8B deming-os.org...
 "Sean L. Palmer" wrote:

 That seems like a really bad design philosophy, because the nature of


 language becomes entirely dependent on the order in which you added the
 features.  If you don't think of the cool features til last, the whole
 language will look like a frankenstein monster.

 Any time you add a feature you need to refactor the existing features.


 there is going to be one way of doing things it should be the best way,


 the first way added.

I agree, and I don't think that that was Walter's strategy. I was

 recognize that one of Walter's key concerns is with orthogonality - he

 features to add new expressive dimensions to the language, not just be

 sugar for old ones.

 IMHO, top_cast is one of those features.

Mar 16 2003