www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Hijacking

reply Walter Bright <newshound1 digitalmars.com> writes:
I want to continue a bit in the Overloading/Inheritance thread which is 
getting a little long, on a closely related issue which I find to be 
important, but so rarely referred to that I had to come up with a name 
for it - hijacking.

Hijacking is when code A depends on B, and then when seemingly unrelated 
code C is modified, then A's behavior silently changes. Here's an 
example from C++:

--A.h--
void foo(long i);

--B.c--
#include "A.h"
#include "C.h"
...
foo(3);    // calls A's foo(long)
--------

Let's say A.h and C.h are developed by different people. In C.h, the 
developer adds:

--C.h--
void foo(int i);
-----

This does something completely different from A.h's foo(long), because 
they just happened to share the same name. Now, when B.c is recompiled, 
it's call to foo is silently *hijacked* by C.h's foo.

Because of C++'s overloading rules and lack of modularity, there's no 
way to programmatically defend against this. Instead, one has to rely on 
coding conventions (such as using a unique package prefix name on all 
symbols, like A_foo() and C_foo()).

So how does this relate to the overloading/inheritance issues? Consider:

----A.d----
class A
{
     ...
}
-----B.d----
import A;
class B : A
{
     void foo(long);
}
...
void bar(B b)
{
     b.foo(3);   // calls B.foo(long)
}
----

Let's say A.d comes from some third party library. Now the developer of 
A decides to add some functionality to class A, and adds the member 
function foo(int):

----A.d---
class A
{
     void foo(int);
}
------------

Now our hapless B programmer has his calls to B.foo(long) silently 
hijacked to A.foo(int) (under Java rules). I don't see any reasonable 
way for B to defend against this. Certainly, developer A doesn't have 
any idea who is deriving from A (and that's the point of polymorphism) - 
but should he be disallowed from adding *any* method names? And the 
hapless B developer, he wrote class B years ago and no longer quite 
remembers how it works, he just recompiles it and now it silently fails.

So, this is one case where I feel C++ got it right, and Java didn't.

(P.S. It's not a compiler implementation issue, nor is it a runtime 
performance issue.)
Aug 05 2007
next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Walter Bright wrote:
 I want to continue a bit in the Overloading/Inheritance thread which is 
 getting a little long, on a closely related issue which I find to be 
 important, but so rarely referred to that I had to come up with a name 
 for it - hijacking.
 
 Hijacking is when code A depends on B, and then when seemingly unrelated 
 code C is modified, then A's behavior silently changes. Here's an 
 example from C++:
 
 --A.h--
 void foo(long i);
 
 --B.c--
 #include "A.h"
 #include "C.h"
 ...
 foo(3);    // calls A's foo(long)
 --------
 
 Let's say A.h and C.h are developed by different people. In C.h, the 
 developer adds:
 
 --C.h--
 void foo(int i);
 -----
 
 This does something completely different from A.h's foo(long), because 
 they just happened to share the same name. Now, when B.c is recompiled, 
 it's call to foo is silently *hijacked* by C.h's foo.
 
 Because of C++'s overloading rules and lack of modularity, there's no 
 way to programmatically defend against this. Instead, one has to rely on 
 coding conventions (such as using a unique package prefix name on all 
 symbols, like A_foo() and C_foo()).
Thank the heavens for D's modules and FQN's. :) You've got that situation covered.
 So how does this relate to the overloading/inheritance issues? Consider:
 
 ----A.d----
 class A
 {
     ...
 }
 -----B.d----
 import A;
 class B : A
 {
     void foo(long);
 }
 ...
 void bar(B b)
 {
     b.foo(3);   // calls B.foo(long)
 }
 ----
 
 Let's say A.d comes from some third party library. Now the developer of 
 A decides to add some functionality to class A, and adds the member 
 function foo(int):
 
 ----A.d---
 class A
 {
     void foo(int);
 }
 ------------
 
 Now our hapless B programmer has his calls to B.foo(long) silently 
 hijacked to A.foo(int) (under Java rules). I don't see any reasonable 
 way for B to defend against this. Certainly, developer A doesn't have 
 any idea who is deriving from A (and that's the point of polymorphism) - 
 but should he be disallowed from adding *any* method names? And the 
 hapless B developer, he wrote class B years ago and no longer quite 
 remembers how it works, he just recompiles it and now it silently fails.
 
 So, this is one case where I feel C++ got it right, and Java didn't.
 
 (P.S. It's not a compiler implementation issue, nor is it a runtime 
 performance issue.)
Alright. I can't argue against that one little bit. I will mention for completeness the option of using an L suffix to explicitly state you want a long... but then there's no analog for explicit int/short/byte, so the problem still exists in any case other than ambiguity against long. (Yes there's cast()... but ew.) -- Chris Nicholson-Sauls
Aug 05 2007
prev sibling next sibling parent reply kris <fu bar.org> writes:
Walter:

There's a related problem where a public method is added to a base-class 
A (as in your example) but where the signature is *exactly* that of one 
existing in derived class B. If A actually calls that new method 
internally, "bad things"tm will almost certainly happen, since B never 
intended to effectively override the newly-added method in A.

This is a very hard problem to isolate yet can be easily remedied by the 
compiler. The request was first made two or three years back, and once 
or twice since then: you make the "override" keyword *required*.

When "override" is required, the compiler can easily trap this related 
type of hijacking and avoid such nasty surprises.




Walter Bright wrote:
 I want to continue a bit in the Overloading/Inheritance thread which is 
 getting a little long, on a closely related issue which I find to be 
 important, but so rarely referred to that I had to come up with a name 
 for it - hijacking.
 
 Hijacking is when code A depends on B, and then when seemingly unrelated 
 code C is modified, then A's behavior silently changes. Here's an 
 example from C++:
 
 --A.h--
 void foo(long i);
 
 --B.c--
 #include "A.h"
 #include "C.h"
 ....
 foo(3);    // calls A's foo(long)
 --------
 
 Let's say A.h and C.h are developed by different people. In C.h, the 
 developer adds:
 
 --C.h--
 void foo(int i);
 -----
 
 This does something completely different from A.h's foo(long), because 
 they just happened to share the same name. Now, when B.c is recompiled, 
 it's call to foo is silently *hijacked* by C.h's foo.
 
 Because of C++'s overloading rules and lack of modularity, there's no 
 way to programmatically defend against this. Instead, one has to rely on 
 coding conventions (such as using a unique package prefix name on all 
 symbols, like A_foo() and C_foo()).
 
 So how does this relate to the overloading/inheritance issues? Consider:
 
 ----A.d----
 class A
 {
     ...
 }
 -----B.d----
 import A;
 class B : A
 {
     void foo(long);
 }
 ....
 void bar(B b)
 {
     b.foo(3);   // calls B.foo(long)
 }
 ----
 
 Let's say A.d comes from some third party library. Now the developer of 
 A decides to add some functionality to class A, and adds the member 
 function foo(int):
 
 ----A.d---
 class A
 {
     void foo(int);
 }
 ------------
 
 Now our hapless B programmer has his calls to B.foo(long) silently 
 hijacked to A.foo(int) (under Java rules). I don't see any reasonable 
 way for B to defend against this. Certainly, developer A doesn't have 
 any idea who is deriving from A (and that's the point of polymorphism) - 
 but should he be disallowed from adding *any* method names? And the 
 hapless B developer, he wrote class B years ago and no longer quite 
 remembers how it works, he just recompiles it and now it silently fails.
 
 So, this is one case where I feel C++ got it right, and Java didn't.
 
 (P.S. It's not a compiler implementation issue, nor is it a runtime 
 performance issue.)
Aug 05 2007
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
kris wrote:
 There's a related problem where a public method is added to a base-class 
 A (as in your example) but where the signature is *exactly* that of one 
 existing in derived class B. If A actually calls that new method 
 internally, "bad things"tm will almost certainly happen, since B never 
 intended to effectively override the newly-added method in A.
 
 This is a very hard problem to isolate yet can be easily remedied by the 
 compiler. The request was first made two or three years back, and once 
 or twice since then: you make the "override" keyword *required*.
 
 When "override" is required, the compiler can easily trap this related 
 type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>. Mitigating factors are private and final methods cannot be overridden.
Aug 05 2007
next sibling parent Mike Capp <mike.capp gmail.com> writes:
Walter Bright Wrote:

[re:making 'override' mandatory]

 That is a good point. The reason I haven't added it is because I'm not 
 sure how annoying it will be to have to always add the 'override' 
 keyword. It might be one of those things like exception specifications 
 where everyone says it's a good idea but guiltily hate in secret <g>.
annoyance in the general case; in fact it normally _saves_ typing since you can just type "override" and ReSharper (a refactoring plugin for VS) offers completions based on virtuals in the base class. And it's been a useful warning of unintended overrides many a time. The one case where the rule does feel annoying is when you have an interface, an abstract base class implementing that interface with pure virtuals while providing common functionality, and a concrete subclass. In D you'd probably mixin the base stuff, so this case wouldn't arise.
Aug 05 2007
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:f95leh$hn4$1 digitalmars.com...
 That is a good point. The reason I haven't added it is because I'm not 
 sure how annoying it will be to have to always add the 'override' keyword. 
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
If anything's annoying, it's when that kind of hijacking happens (I've had it bite me a few times). I _always_ try to put override on every method that I override, as not only is it self-documenting, but it also traps this kind of bug.
Aug 05 2007
prev sibling next sibling parent reply kris <fu bar.org> writes:
Walter Bright wrote:
 kris wrote:
 
 There's a related problem where a public method is added to a 
 base-class A (as in your example) but where the signature is *exactly* 
 that of one existing in derived class B. If A actually calls that new 
 method internally, "bad things"tm will almost certainly happen, since 
 B never intended to effectively override the newly-added method in A.

 This is a very hard problem to isolate yet can be easily remedied by 
 the compiler. The request was first made two or three years back, and 
 once or twice since then: you make the "override" keyword *required*.

 When "override" is required, the compiler can easily trap this related 
 type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>.
Let's put it this way: I have a personal and quite open dislike for exception specifications, yet I try very hard to ensure override is added in all the right places in D, even though the compiler doesn't enforce it. In other words, I go to the trouble of adding override for the benefit of manual auditing. The compiler ought to be helping me with that task? - Kris
Aug 06 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
kris wrote:
 In other words, I go to the trouble of adding override for the benefit 
 of manual auditing. The compiler ought to be helping me with that task?
I'll put it in as a warning in the next update, and we can try it out.
Aug 06 2007
prev sibling next sibling parent reply eao197 <eao197 intervale.ru> writes:
On Mon, 06 Aug 2007 03:11:14 +0400, Walter Bright  
<newshound1 digitalmars.com> wrote:

 kris wrote:
 There's a related problem where a public method is added to a  
 base-class A (as in your example) but where the signature is *exactly*  
 that of one existing in derived class B. If A actually calls that new  
 method internally, "bad things"tm will almost certainly happen, since B  
 never intended to effectively override the newly-added method in A.
  This is a very hard problem to isolate yet can be easily remedied by  
 the compiler. The request was first made two or three years back, and  
 once or twice since then: you make the "override" keyword *required*.
  When "override" is required, the compiler can easily trap this related  
 type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>.
Eiffel has same feature for more than 20 years and it really works :) Each method which derived class wants to redefine must be declared in special section: class BASE feature a is ... end b is ... end c is ... end end class DERIVED inherit BASE redefine a, b end feature a is ... end b is ... end end It is error if 'c' is defined in DERIVED without specifying in 'redefine' section. In addition, Scala requires to use 'override' keyword and it also works fine. -- Regards, Yauheni Akhotnikau
Aug 06 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
eao197 wrote:
 Eiffel has same feature for more than 20 years and it really works :)
Eiffel has many good ideas, but we must be careful thinking of Eiffel as an endorsement, as it failed to catch on. I think one reason it failed is because of the syntax.
Aug 06 2007
next sibling parent eao197 <eao197 intervale.ru> writes:
On Mon, 06 Aug 2007 21:30:43 +0400, Walter Bright  =

<newshound1 digitalmars.com> wrote:

 eao197 wrote:
 Eiffel has same feature for more than 20 years and it really works :)=
 Eiffel has many good ideas, but we must be careful thinking of Eiffel =
as =
 an endorsement, as it failed to catch on. I think one reason it failed=
=
 is because of the syntax.
No, I don't think so. I spent last 1.5 month to study Eiffel. Eiffel = syntax isn't a problem (moreover I think Eiffel/Ruby syntax is more = attractive than old C curly braces tradition). By main opinion the main Eiffel's problems are: 1. Only one paradim. Only OOP and only by following the Eiffel method. 2. Comand/query separation principle. For example, you can't do somethin= g = with object and get the result, as in C++/D: auto sent_result =3D mail_box.send_message(msg); In Eiffel send_message must be command, and mail_box must have a query t= o = retrive last send result: local send_result: SEND_RESULT do mail_box.send_message (msg) send_result :=3D mail_box.last_send_result ... end 3. Very different exception mechanism. For example see my question about= = resouce cleanup in the case of exception: = http://tech.groups.yahoo.com/group/eiffel_software/message/11062 But 'DesignByContract' and inheritance (and various forms of inheritance= = conflicts resolving) are really great part of Eiffel. So I vote for mandatory 'override' keyword in D too. -- = Regards, Yauheni Akhotnikau
Aug 06 2007
prev sibling parent reply Charles D Hixson <charleshixsn earthlink.net> writes:
Walter Bright wrote:
 eao197 wrote:
 Eiffel has same feature for more than 20 years and it really works :)
Eiffel has many good ideas, but we must be careful thinking of Eiffel as an endorsement, as it failed to catch on. I think one reason it failed is because of the syntax.
My suspicion of the reason that Eiffel failed to catch on is the personality and resultant policies of the designer. It took a long time for SmallEiffel to be released...and it's policies aren't that friendly, either, even though it IS GPL software. OTOH, IMNSHO, Eiffel did make a few serious mistakes. One of them was in forbidding two different functions (essentially the same) to be distinguished by their argument list, but not by their name. BAD decision. So you're right when you say "be careful", but don't attribute most of the failure of Eiffel to it's design. Other factors predominated. Note that D already had three branches DMD1, DMD2, and gdc. And that they share a lot of the same code (which keeps duplicate effort to a minimum). If you want to copy organization policies, copy from Python, but Eiffel had very many good ideas that a compiler language could benefit from. (I'm not as convinced by modern versions of Eiffel as I was by the earlier ones...but then I've basically stopped following it, because it kept breaking all of it's libraries with each new release. And it never did become as easy to link to C as D already is. [Now if only there was a decent way to manage C++ linkage.])
Aug 06 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Charles D Hixson wrote:
 So you're right when you say "be careful", but don't attribute most of 
 the failure of Eiffel to it's design.  Other factors predominated.
For a complex thing like a language, it can be really hard to pin down why it failed. Ask n different people, and you'll get n different answers. What turned me off was the syntax. It just means we have to be extra careful about adopting features from a failed language. The further a feature is from mainstream convention in at least one successful language, the more nervous I get about it.
Aug 06 2007
prev sibling next sibling parent reply Regan Heath <regan netmail.co.nz> writes:
Walter Bright wrote:
 kris wrote:
 There's a related problem where a public method is added to a 
 base-class A (as in your example) but where the signature is *exactly* 
 that of one existing in derived class B. If A actually calls that new 
 method internally, "bad things"tm will almost certainly happen, since 
 B never intended to effectively override the newly-added method in A.

 This is a very hard problem to isolate yet can be easily remedied by 
 the compiler. The request was first made two or three years back, and 
 once or twice since then: you make the "override" keyword *required*.

 When "override" is required, the compiler can easily trap this related 
 type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>. Mitigating factors are private and final methods cannot be overridden.
My vote was, and still is, for 'override' to be mandatory. Regan
Aug 06 2007
next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Regan Heath wrote:
 Walter Bright wrote:
 kris wrote:
 There's a related problem where a public method is added to a 
 base-class A (as in your example) but where the signature is 
 *exactly* that of one existing in derived class B. If A actually 
 calls that new method internally, "bad things"tm will almost 
 certainly happen, since B never intended to effectively override the 
 newly-added method in A.

 This is a very hard problem to isolate yet can be easily remedied by 
 the compiler. The request was first made two or three years back, and 
 once or twice since then: you make the "override" keyword *required*.

 When "override" is required, the compiler can easily trap this 
 related type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>. Mitigating factors are private and final methods cannot be overridden.
My vote was, and still is, for 'override' to be mandatory. Regan
Me too. Note that since you can use 'override { }' or 'override:', it's less onerous than putting 'virtual' in front of every function in C++.
Aug 06 2007
parent reply Sean Kelly <sean f4.ca> writes:
Don Clugston wrote:
 Me too. Note that since you can use 'override { }' or 'override:', it's 
 less onerous than putting 'virtual' in front of every function in C++.
How does "override:" work with other properties used as labels? Is it disabled when public/protected/private is next used in the same way? Sean
Aug 06 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 How does "override:" work with other properties used as labels?  Is it 
 disabled when public/protected/private is next used in the same way?
It adds to them.
Aug 06 2007
parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Sean Kelly wrote:
 How does "override:" work with other properties used as labels?  Is it 
 disabled when public/protected/private is next used in the same way?
It adds to them.
So is there anyway to disable "override:" once set? Sean
Aug 06 2007
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 Sean Kelly wrote:
 How does "override:" work with other properties used as labels?  Is 
 it disabled when public/protected/private is next used in the same way?
It adds to them.
So is there anyway to disable "override:" once set? Sean
Since there is no "not an override" keyword, I would wager there isn't. (Unless for end of current scope, aye? But even then...) I don't think we really need a non-override keyword, and I wouldn't want 'final' to be given that effect either ('final override' should be a valid attribute), or any other existing attributes... so our options are: attribute. Maybe '!foo:' or similar. -- Chris Nicholson-Sauls
Aug 06 2007
next sibling parent Sean Kelly <sean f4.ca> writes:
Chris Nicholson-Sauls wrote:
 

 

Same here. Using "override:" doesn't seem feasible in all but the simplest cases. Sean
Aug 06 2007
prev sibling parent =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= writes:
Chris Nicholson-Sauls wrote:
  > I don't think we really need a non-override keyword, and I wouldn't 
want
 'final' to be given that effect either ('final override' should be a 
 valid attribute), or any other existing attributes... so our options are:
 

 attribute.  Maybe '!foo:' or similar.
 

 

 
 -- Chris Nicholson-Sauls
override: void foo() {} void bar() {} default: void baz() {} But then again, maybe in this case we should just use override {} or reorder methods.
Aug 07 2007
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 Sean Kelly wrote:
 How does "override:" work with other properties used as labels?  Is 
 it disabled when public/protected/private is next used in the same way?
It adds to them.
So is there anyway to disable "override:" once set?
No.
Aug 06 2007
prev sibling parent reply Frank Benoit <keinfarbton googlemail.com> writes:
Regan Heath schrieb:

 My vote was, and still is, for 'override' to be mandatory.
 
 Regan
As said in my posting http://www.digitalmars.com/d/archives/digitalmars/D/aliasing_base_methods_49572.html#N49577 , i still second that also.
Aug 06 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Frank Benoit Wrote:

 Regan Heath schrieb:
 
 My vote was, and still is, for 'override' to be mandatory.
 
 Regan
As said in my posting http://www.digitalmars.com/d/archives/digitalmars/D/aliasing_base_methods_49572.html#N49577 , i still second that also.
votes++; It's really not that hard and will catch a lot of errors. Plus, a good IDE can insert that stuff automatically.
Aug 06 2007
prev sibling next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Walter Bright wrote:
 keyword. It might be one of those things like exception specifications 
 where everyone says it's a good idea but guiltily hate in secret <g>.
 
I don't think the mainstream opinion in Java is that checked exceptions are a good ideia. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 06 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Bruno Medeiros wrote:
 Walter Bright wrote:
 keyword. It might be one of those things like exception specifications 
 where everyone says it's a good idea but guiltily hate in secret <g>.
I don't think the mainstream opinion in Java is that checked exceptions are a good ideia.
It's not a great analogy, because there are very good technical arguments against checked exceptions. But I do remember prominent Java people promoting checked exceptions as a great idea, while in their own code they'd subvert them because they were just too annoying. I also think that mainstream Java has evolved its understanding of checked exceptions.
Aug 06 2007
prev sibling next sibling parent reply "Rioshin an'Harthen" <rharth75 hotmail.com> writes:
"Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Aug 06 2007
parent reply "Nick Sabalausky" <a a.a> writes:
"Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message 
news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
Aug 06 2007
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Nick Sabalausky wrote:
 "Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message 
 news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
I didn't mind it at first, in that the Java compiler would then let me know if I'd missed any potential exceptions... ...but when I noticed I was just adding 'throws A,B,C' to a lot of my methods, I decided it wasn't entirely a great thing afterall. What would have been better, I think, would have been to make throws specifications /optional/. A thing libraries should do, but which applications should be allowed to quietly "forget" most of the time. Java is the language of conventions, after all. -- Chris Nicholson-Sauls
Aug 06 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Chris Nicholson-Sauls Wrote:

 Nick Sabalausky wrote:
 "Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message 
 news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
I didn't mind it at first, in that the Java compiler would then let me know if I'd missed any potential exceptions... ...but when I noticed I was just adding 'throws A,B,C' to a lot of my methods, I decided it wasn't entirely a great thing afterall. What would have been better, I think, would have been to make throws specifications /optional/. A thing libraries should do, but which applications should be allowed to quietly "forget" most of the time. Java is the language of conventions, after all. -- Chris Nicholson-Sauls
I'd like it to be required in the method where the exception is thrown for checked exceptions, but not in any calling methods (they're just optional there). But I'm not too passionate about the point... I can live with 'em (they're a bit annoying, but I can see their advantages), and I can live without 'em.
Aug 06 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Nick Sabalausky wrote:
 "Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message 
 news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
I agree with this 100%. With check exceptions it just becomes too annoying and verbose. Without them, often it is too difficult to find out what exceptions are possible for a function to throw. So the right place seems to be an analysis / doc-generation tool / IDE. --bb
Aug 07 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 Nick Sabalausky wrote:
 "Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message 
 news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where 
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
I agree with this 100%. With check exceptions it just becomes too annoying and verbose. Without them, often it is too difficult to find out what exceptions are possible for a function to throw. So the right place seems to be an analysis / doc-generation tool / IDE. --bb
Interesting thing I'd like to mention, again about how IDEs affect the language design and influence it's advantages and disadvantages. I too find checked exceptions annoying, but this is an example of a language disadvantage has been practically nullified by the IDE (JDT). First I took a slightly modified ExceptionAdapter class such as the one from Bruce Eckel's article: http://www.mindview.net/Etc/Discussions/CheckedExceptions (basicly ExceptionAdapter is class that wraps a checked exception in an unchecked exception, allowing it to be thrown unchecked) So when you have something like this: foo.doSomething(); // throws a normal exception and Java will complain that an exception is thrown, you add this: try { foo.doSomething(); // throws a normal exception } catch(FooException fe) { ExceptionAdapter.unchecked(fe); } and there is no longer a compiler error (unchecked is a static method that wraps the exception), without having needed to put throws clauses in all method along the call hierarchy. This is an interesting workaround, but it is still annoying to have to write that try-catch code whenever an exception is thrown. The second part is where JDT comes in. Whenever you have this: foo.doSomething(); // throws a normal exception the IDE compiler will show and highlight the error, and then you can press Ctrl+1 on the error (Quick-Assist), showing a list of possible fixes, one of them being "Surround with Try-Catch". If you select it, JDT will automatically add the try-catch code, like this: try { foo.doSomething(); // throws a normal exception } catch(FooException fe) { // TODO: catch exception here } Note that the catch clause is automatically set to the thrown exception. But furthermore you can change the template of code that is created with this try-catch quick-fix, so that instead of the "// TODO:" line, you put the "ExceptionAdapter.unchecked(...);" line. So now whenever this quick fix is invoked, it will automatically generate all necessary code, and you're now able to avoid the checked exception problem with just a few keystrokes (Ctrl+1, Down, Enter). :) As an added bonus, if some time you feel the need to rigorously specify your code, you can then search for calls of the ExceptionAdapter.unchecked method, to find points where you can turn unchecked exceptions into checked ones. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 08 2007
parent reply eao197 <eao197 intervale.ru> writes:
On Wed, 08 Aug 2007 15:38:14 +0400, Bruno Medeiros  
<brunodomedeiros+spam com.gmail> wrote:

 Bill Baxter wrote:
 Nick Sabalausky wrote:
 "Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message  
 news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä  
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications where  
 everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
I agree with this 100%. With check exceptions it just becomes too annoying and verbose. Without them, often it is too difficult to find out what exceptions are possible for a function to throw. So the right place seems to be an analysis / doc-generation tool / IDE. --bb
Interesting thing I'd like to mention, again about how IDEs affect the language design and influence it's advantages and disadvantages. I too find checked exceptions annoying, but this is an example of a language disadvantage has been practically nullified by the IDE (JDT). First I took a slightly modified ExceptionAdapter class such as the one from Bruce Eckel's article: http://www.mindview.net/Etc/Discussions/CheckedExceptions (basicly ExceptionAdapter is class that wraps a checked exception in an unchecked exception, allowing it to be thrown unchecked) So when you have something like this: foo.doSomething(); // throws a normal exception and Java will complain that an exception is thrown, you add this: try { foo.doSomething(); // throws a normal exception } catch(FooException fe) { ExceptionAdapter.unchecked(fe); } and there is no longer a compiler error (unchecked is a static method that wraps the exception), without having needed to put throws clauses in all method along the call hierarchy. This is an interesting workaround, but it is still annoying to have to write that try-catch code whenever an exception is thrown. The second part is where JDT comes in. Whenever you have this: foo.doSomething(); // throws a normal exception the IDE compiler will show and highlight the error, and then you can press Ctrl+1 on the error (Quick-Assist), showing a list of possible fixes, one of them being "Surround with Try-Catch". If you select it, JDT will automatically add the try-catch code, like this: try { foo.doSomething(); // throws a normal exception } catch(FooException fe) { // TODO: catch exception here } Note that the catch clause is automatically set to the thrown exception. But furthermore you can change the template of code that is created with this try-catch quick-fix, so that instead of the "// TODO:" line, you put the "ExceptionAdapter.unchecked(...);" line. So now whenever this quick fix is invoked, it will automatically generate all necessary code, and you're now able to avoid the checked exception problem with just a few keystrokes (Ctrl+1, Down, Enter). :) As an added bonus, if some time you feel the need to rigorously specify your code, you can then search for calls of the ExceptionAdapter.unchecked method, to find points where you can turn unchecked exceptions into checked ones.
I don't agree (almost complitely). Checked expession is not simply annoying. Sometimes they lead to bad-style and erroneous code. For example imagine you redefine some method: class MySpecializedClass extends SomeGeneralClass { public void someMethod() throws DomainSpecificException { ... } } but you need to use temporary file in someMethod() implementation (or need to run some external tool, or need to use some crypto library). And File.createTempFile throws IllegalArgumentException or IOException or SecurityException, but no one of them is in someMethod 'throws' clause. In such case you have only two possibilities: wrap the exception which is thrown by File.createTempFile into some another exception (it is good if DomainSpecificException allows that, but in an usual case it don't) or catch and hide the original exception. As I seen in the past many developers prefered catch and hide exception. And this is not a good approach I think. So in my opinion it is better to write code which doesn't depend on particular kind of exception. Assumption that any part of code could throws any kind of exception lead to more reliable software (Erlang is an evidence). The exception safety in much more hard in C++ where there is manual memory management and there isn't scope()-constructs like in D. So I hope that writting exception safe code in D is much more easy, than in C++ or in Java with checked exceptions. However sometimes is good to know that some method doesn't throw exception at all (it could be necessary for exception safety, like C++ convection that swap() methods and destructors are exception free). So I suppose to introduce 'nothrows' modifier as a sign that some routine is exception free: bool is_item_in_array( int[] array, int item ) nothrows { ... } Compiler could checks nothrows-routines. It is an error if nothrows-routine calls any routine without 'nothrows' modifier. So it could be an crear advice to programmer: if it has some data which must be protected from exception and he calls any routine without 'nothrows' modifier he must do some action to protect his data. -- Regards, Yauheni Akhotnikau
Aug 08 2007
next sibling parent eao197 <eao197 intervale.ru> writes:
On Wed, 08 Aug 2007 17:05:07 +0400, eao197 <eao197 intervale.ru> wrote:

 So in my opinion it is better to write code which doesn't depend on  =
 particular kind of exception. Assumption that any part of code could  =
 throws any kind of exception lead to more reliable software (Erlang is=
=
 an evidence).

 The exception safety in much more hard in C++ where there is manual  =
 memory management and there isn't scope()-constructs like in D. So I  =
 hope that writting exception safe code in D is much more easy, than in=
=
 C++ or in Java with checked exceptions.

 However sometimes is good to know that some method doesn't throw  =
 exception at all (it could be necessary for exception safety, like  =
 C++ convection that swap() methods and destructors are exception free)=
. =
 So I suppose to introduce 'nothrows' modifier as a sign that some  =
 routine is exception free:

 bool is_item_in_array( int[] array, int item ) nothrows { ... }

 Compiler could checks nothrows-routines. It is an error if  =
 nothrows-routine calls any routine without 'nothrows' modifier.

 So it could be an crear advice to programmer: if it has some data whic=
h =
 must be protected from exception and he calls any routine without  =
 'nothrows' modifier he must do some action to protect his data.
Yet more ideas about 'nothrows' modifier (sorry for wasting your time). Which routines need 'nothrows' specifications? Obvious (for me) answer is: various forms of cleanup-routines. For = example: File.close, Mutex.release, DbConnection.disconnect and so on. = E.g. routines which will be used in destructors, scope-constructs and = finally-blocks. So, compiler could checks all calls in those constructs = = and reports warning (or even errors) if any method without 'nothrows' is= = being called. Even more. In some situation cleanup actions could be performed in = catch-blocks. To ensure that no exception will be thrown during cleanup = = programmer could write: nothrows { ... // some actions... } and compiler will check all calls in such block. For example: // Create new DB connection for user. // And checks user right. If user has no right (has expiried password) t= hen // exception is thrown. UserSession open_user_section( string user_name, string user_password ) { auto db_connection =3D establish_db_connection(); try { check_user_rights( db_connection, user_name, user_password ); ... // Some other actions... } catch( Exception x ) { nothrows { cleanup_db_connection( db_connection ); ... // Some other cleanup actions... } log_session_creation_error( x ); throw; } return new UserSession( db_connection, user_name ); } So compiler could check that no exception is allowed in cleanup actions.= = But new exception could be thrown in 'log_session_creation_error' method= . -- = Regards, Yauheni Akhotnikau
Aug 08 2007
prev sibling next sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
eao197 wrote:
 However sometimes is good to know that some method doesn't throw 
 exception at all (it could be necessary for exception safety, like C++ 
 convection that swap() methods and destructors are exception free). So I 
 suppose to introduce 'nothrows' modifier as a sign that some routine is 
 exception free:
The compiler can support this. It'd have to add more metadata to precompiled libraries, but that's okay. The ddocs could then (optionally?) include information on what exceptions the function throws directly and what other exceptions can be thrown on invocation. So I don't see any reason for the programmer to have to manually do all this. -cbw
Aug 09 2007
parent eao197 <eao197 intervale.ru> writes:
On Fri, 10 Aug 2007 06:03:10 +0400, Christopher Wright  =

<dhasenan gmail.com> wrote:

 eao197 wrote:
 However sometimes is good to know that some method doesn't throw  =
 exception at all (it could be necessary for exception safety, like C+=
+ =
 convection that swap() methods and destructors are exception free). S=
o =
 I suppose to introduce 'nothrows' modifier as a sign that some routin=
e =
 is exception free:
The compiler can support this. It'd have to add more metadata to =
 precompiled libraries, but that's okay. The ddocs could then  =
 (optionally?) include information on what exceptions the function thro=
ws =
 directly and what other exceptions can be thrown on invocation.

 So I don't see any reason for the programmer to have to manually do al=
l =
 this.
There are one important use case where the compiler can't detect which = exceptions are thrown by a method: polymorphism and late binding. Imagin= e: class EventHandler { abstract void handle_input(); abstract void handle_output(); abstract void handle_exception(); ... } class SelectReactor : Reactor { void reactor_event_loop() { while( true ) { EventHandler[] input_ready_handlers =3D = detect_input_ready_handlers(); foreach( h; input_ready_handlers ) h.handle_input(); ... } } } During compilation of SelectReactor the compiler can't determine which = exception could be thrown by descendants of EventHandler. So it is a = programmer's task to specify exceptions in 'throws' clause (like in = 'nothrows' clause (like throw() in C++). -- = Regards, Yauheni Akhotnikau
Aug 09 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
eao197 wrote:
 On Wed, 08 Aug 2007 15:38:14 +0400, Bruno Medeiros 
 <brunodomedeiros+spam com.gmail> wrote:
 
 Bill Baxter wrote:
 Nick Sabalausky wrote:
 "Rioshin an'Harthen" <rharth75 hotmail.com> wrote in message 
 news:f974u9$9k1$1 digitalmars.com...
 "Walter Bright" <newshound1 digitalmars.com> kirjoitti viestissä 
 news:f95leh$hn4$1 digitalmars.com...
 It might be one of those things like exception specifications 
 where everyone says it's a good idea but guiltily hate in secret <g>.
Exception specification *is* a good idea. Although I do hate it - try to remember what a specific method may throw when you write your code, especially if the error is ambiguous like "Unhandled exception" it's really irritating - but I hate unspecified exceptions even more, as the problem then is to even remember to put in the necessary try-catch-finally blocks.
Not to start a big big debate on it, but my own personal feeling on that (after having used a fair amount of it) is that the specification of exceptions belongs in generated documentation (whether javadoc-style or as part of the IDE as with "some_function() -> Called By..."). I normally prefer having to explicity specify things (yea, strong-typing fan here ;) ), but personally, I find it overkill in this case. (Not to mention it gave me flashbacks of writing C/C++ headers. j/k ;) ).
I agree with this 100%. With check exceptions it just becomes too annoying and verbose. Without them, often it is too difficult to find out what exceptions are possible for a function to throw. So the right place seems to be an analysis / doc-generation tool / IDE. --bb
Interesting thing I'd like to mention, again about how IDEs affect the language design and influence it's advantages and disadvantages. I too find checked exceptions annoying, but this is an example of a language disadvantage has been practically nullified by the IDE (JDT). First I took a slightly modified ExceptionAdapter class such as the one from Bruce Eckel's article: http://www.mindview.net/Etc/Discussions/CheckedExceptions (basicly ExceptionAdapter is class that wraps a checked exception in an unchecked exception, allowing it to be thrown unchecked) So when you have something like this: foo.doSomething(); // throws a normal exception and Java will complain that an exception is thrown, you add this: try { foo.doSomething(); // throws a normal exception } catch(FooException fe) { ExceptionAdapter.unchecked(fe); } and there is no longer a compiler error (unchecked is a static method that wraps the exception), without having needed to put throws clauses in all method along the call hierarchy. This is an interesting workaround, but it is still annoying to have to write that try-catch code whenever an exception is thrown. The second part is where JDT comes in. Whenever you have this: foo.doSomething(); // throws a normal exception the IDE compiler will show and highlight the error, and then you can press Ctrl+1 on the error (Quick-Assist), showing a list of possible fixes, one of them being "Surround with Try-Catch". If you select it, JDT will automatically add the try-catch code, like this: try { foo.doSomething(); // throws a normal exception } catch(FooException fe) { // TODO: catch exception here } Note that the catch clause is automatically set to the thrown exception. But furthermore you can change the template of code that is created with this try-catch quick-fix, so that instead of the "// TODO:" line, you put the "ExceptionAdapter.unchecked(...);" line. So now whenever this quick fix is invoked, it will automatically generate all necessary code, and you're now able to avoid the checked exception problem with just a few keystrokes (Ctrl+1, Down, Enter). :) As an added bonus, if some time you feel the need to rigorously specify your code, you can then search for calls of the ExceptionAdapter.unchecked method, to find points where you can turn unchecked exceptions into checked ones.
I don't agree (almost complitely). Checked expession is not simply annoying. Sometimes they lead to bad-style and erroneous code. For example imagine you redefine some method: class MySpecializedClass extends SomeGeneralClass { public void someMethod() throws DomainSpecificException { ... } } but you need to use temporary file in someMethod() implementation (or need to run some external tool, or need to use some crypto library). And File.createTempFile throws IllegalArgumentException or IOException or SecurityException, but no one of them is in someMethod 'throws' clause. In such case you have only two possibilities: wrap the exception which is thrown by File.createTempFile into some another exception (it is good if DomainSpecificException allows that, but in an usual case it don't) or catch and hide the original exception. As I seen in the past many developers prefered catch and hide exception. And this is not a good approach I think. So in my opinion it is better to write code which doesn't depend on particular kind of exception. Assumption that any part of code could throws any kind of exception lead to more reliable software (Erlang is an evidence).
I don't see how that is disagreeing with what I said before. Note that the above doesn't hide the exception (as in, make it disappear), it gets re-thrown as an unchecked exception. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 10 2007
parent reply eao197 <eao197 intervale.ru> writes:
On Fri, 10 Aug 2007 14:15:47 +0400, Bruno Medeiros  
<brunodomedeiros+spam com.gmail> wrote:

 I don't see how that is disagreeing with what I said before. Note that  
 the above doesn't hide the exception (as in, make it disappear), it gets  
 re-thrown as an unchecked exception.
Umm... I'm sorry, I thought that 'ExceptionAdapter.unchecked(fe)' simply hides exception. But initaly I was disagree with that:
 an example of a language disadvantage has been practically nullified by  
 the IDE (JDT).
Easy method of incapsulating exception into unchecked one doesn't repair flaw in the language design. -- Regards, Yauheni Akhotnikau
Aug 10 2007
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
eao197 wrote:
 On Fri, 10 Aug 2007 14:15:47 +0400, Bruno Medeiros 
 <brunodomedeiros+spam com.gmail> wrote:
 
 I don't see how that is disagreeing with what I said before. Note that 
 the above doesn't hide the exception (as in, make it disappear), it 
 gets re-thrown as an unchecked exception.
Umm... I'm sorry, I thought that 'ExceptionAdapter.unchecked(fe)' simply hides exception.
No, it doesn't do that. And indeed it would be bad if it did.
 But initaly I was disagree with that:
 
 an example of a language disadvantage has been practically nullified 
 by the IDE (JDT).
Easy method of incapsulating exception into unchecked one doesn't repair flaw in the language design.
It fixes it well enough for me. :) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 10 2007
prev sibling next sibling parent 0ffh <spam frankhirsch.net> writes:
Walter Bright wrote:
 That is a good point. The reason I haven't added it is because I'm not 
 sure how annoying it will be to have to always add the 'override' 
 keyword. It might be one of those things like exception specifications 
 where everyone says it's a good idea but guiltily hate in secret <g>.
Hmmmm... even I think that requiring the override keyword is okay, and I am not exactly known to be a discipline and bondage fanatic. ^^ Regards, Frank
Aug 06 2007
prev sibling next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Walter,

 kris wrote:
 
 There's a related problem where a public method is added to a
 base-class A (as in your example) but where the signature is
 *exactly* that of one existing in derived class B. If A actually
 calls that new method internally, "bad things"tm will almost
 certainly happen, since B never intended to effectively override the
 newly-added method in A.
 
 This is a very hard problem to isolate yet can be easily remedied by
 the compiler. The request was first made two or three years back, and
 once or twice since then: you make the "override" keyword *required*.
 
 When "override" is required, the compiler can easily trap this
 related type of hijacking and avoid such nasty surprises.
 
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>. Mitigating factors are private and final methods cannot be overridden.
How hard would it be to put a command line flag on the 2.0 version that would turn it on?
Aug 06 2007
parent reply 0ffh <spam frankhirsch.net> writes:
BCS wrote:
 Reply to Walter,
 How hard would it be to put a command line flag on the 2.0 version that 
 would turn it on?
[Compulsory override keyword, I presume] Or rather, one to turn it off? ;-) Regards, Frank
Aug 06 2007
parent BCS <ao pathlink.com> writes:
Reply to 0ffh,

 BCS wrote:
 
 Reply to Walter,
 How hard would it be to put a command line flag on the 2.0 version
 that
 would turn it on?
[Compulsory override keyword, I presume] Or rather, one to turn it off? ;-) Regards, Frank
either
Aug 06 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 kris wrote:
 There's a related problem where a public method is added to a 
 base-class A (as in your example) but where the signature is *exactly* 
 that of one existing in derived class B. If A actually calls that new 
 method internally, "bad things"tm will almost certainly happen, since 
 B never intended to effectively override the newly-added method in A.

 This is a very hard problem to isolate yet can be easily remedied by 
 the compiler. The request was first made two or three years back, and 
 once or twice since then: you make the "override" keyword *required*.

 When "override" is required, the compiler can easily trap this related 
 type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>. Mitigating factors are private and final methods cannot be overridden.
Although, I generally like the idea, I fear that requiring 'override' will have side effects for mixins. The writer of the mixin has no way of knowing if the methods will override something or not. I'm thinking the only reasonable solution would be to allow mixins to go on as they currently are, without enforcing the use of 'override'. However, an accidental override that comes in via a mixin seems like a very likely source of subtle bugs. And requiring a special exception to the rules is not really desirable in the first place. --bb
Aug 07 2007
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 Although, I generally like the idea, I fear that requiring 'override' 
 will have side effects for mixins.  The writer of the mixin has no way 
 of knowing if the methods will override something or not.
I didn't think of that. But I'll put the check in as a warning, and we'll see if there are real problems or not.
Aug 07 2007
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 Although, I generally like the idea, I fear that requiring 'override' 
 will have side effects for mixins.  The writer of the mixin has no way 
 of knowing if the methods will override something or not.
I didn't think of that. But I'll put the check in as a warning, and we'll see if there are real problems or not.
There are probably on two likely scenarios for that: user to a potential (serious) hazard. On the other hand, if the overlap is not an issue, or even on purpose, the workaround is clumsy and kludgy: class B { int foo() {...} } template M { int foo() {...} int bar() {...} } class D : B { mixin M _m; alias _m.bar bar; override int foo () { return _m.foo(); } } Chances are that a relative straightforward CheckOverrides() template or CTF could be used to auto-generate this. There is still, however, the issue of a superfluous proxy method being written, whether by the programmer or by CheckOverrides(). In the first, the situation is an accident. Perhaps D was not previously derived from B, but is now as a result of refactoring, and the unnecessary mixin statement was simply missed. The compiler has caught a programmer error. Good Thing. In the second, perhaps class B had overwritten some of the mixin's methods to behave differently, and class D intends to re-mix the default behavior (perhaps to expose its own changes). In this case perhaps one could wrap the mixin statement and subsequent overwrites in an 'override {...}' block and be good to go. template M { int foo() {...} int bar() {...} } class B { mixin M; int foo() {...custom version...} } class D : B { override { mixin M; int bar() {...custom version...} } } It makes for nice grouping as well, even if it is a workaround. Of course I might have missed some other case where this could happen. -- Chris Nicholson-Sauls
Aug 07 2007
prev sibling parent Reiner Pope <some address.com> writes:
Bill Baxter wrote:
 Walter Bright wrote:
 kris wrote:
 There's a related problem where a public method is added to a 
 base-class A (as in your example) but where the signature is 
 *exactly* that of one existing in derived class B. If A actually 
 calls that new method internally, "bad things"tm will almost 
 certainly happen, since B never intended to effectively override the 
 newly-added method in A.

 This is a very hard problem to isolate yet can be easily remedied by 
 the compiler. The request was first made two or three years back, and 
 once or twice since then: you make the "override" keyword *required*.

 When "override" is required, the compiler can easily trap this 
 related type of hijacking and avoid such nasty surprises.
That is a good point. The reason I haven't added it is because I'm not sure how annoying it will be to have to always add the 'override' keyword. It might be one of those things like exception specifications where everyone says it's a good idea but guiltily hate in secret <g>. Mitigating factors are private and final methods cannot be overridden.
Although, I generally like the idea, I fear that requiring 'override' will have side effects for mixins. The writer of the mixin has no way of knowing if the methods will override something or not. I'm thinking the only reasonable solution would be to allow mixins to go on as they currently are, without enforcing the use of 'override'. However, an accidental override that comes in via a mixin seems like a very likely source of subtle bugs. And requiring a special exception to the rules is not really desirable in the first place. --bb
Interesting point. I think, however, that an explicit solution which re-enables using mixins as overriding functions is the best solution (as you point out, the alternative is subtle bugs). Perhaps a new form of alias, to add the override? template Foo() { int foo() { return x*x; } } class Base { int foo() { return 5; } } class Derived : Base { int x = 5; mixin Foo my_foo; // specify that my_foo.foo overrides Base.foo alias my_foo.foo Base.foo; // or specify that my_foo.foo is an override alias my_foo.foo override foo; // (but obviously not both at once) } -- Reiner PS. Notice how I've (not-so-)subtly worked in my suggestion from http://www.digitalmars.com/d/archives/digitalmars/D/Implementing_required_methods_w th_alias_56011.html ;-)
Aug 08 2007
prev sibling parent "Chris Miller" <chris dprogramming.com> writes:
 This is a very hard problem to isolate yet can be easily remedied by the  
 compiler. The request was first made two or three years back, and once  
 or twice since then: you make the "override" keyword *required*.
I'm for this. I feel funny when I don't use "override".
Aug 06 2007
prev sibling next sibling parent Regan Heath <regan netmail.co.nz> writes:
This post looks like a prime candidate for an article page on the D 
website (with "Const", "Memory Management", etc).

Regan
Aug 06 2007
prev sibling next sibling parent Ender KaShae <astrothayne gmail.com> writes:
kris Wrote:

 Walter:
 
 There's a related problem where a public method is added to a base-class 
 A (as in your example) but where the signature is *exactly* that of one 
 existing in derived class B. If A actually calls that new method 
 internally, "bad things"tm will almost certainly happen, since B never 
 intended to effectively override the newly-added method in A.
 
 This is a very hard problem to isolate yet can be easily remedied by the 
 compiler. The request was first made two or three years back, and once 
 or twice since then: you make the "override" keyword *required*.
 
 When "override" is required, the compiler can easily trap this related 
 type of hijacking and avoid such nasty surprises.
 
if the function is overrided ONLY when the override keyword is there would prevent prevent any errors when such an action occurrs, but you also run into the bittersweet situation of hiding members of the base class.
Aug 06 2007
prev sibling next sibling parent reply Derek Parnell <derek psyc.ward> writes:
On Sun, 05 Aug 2007 11:47:18 -0700, Walter Bright wrote:

 I want to continue a bit in the Overloading/Inheritance thread which is 
 getting a little long, on a closely related issue which I find to be 
 important, but so rarely referred to that I had to come up with a name 
 for it - hijacking.
I'm just wondering what the NSA is making of this discussion :) -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 06 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Derek Parnell wrote:
 On Sun, 05 Aug 2007 11:47:18 -0700, Walter Bright wrote:
 
 I want to continue a bit in the Overloading/Inheritance thread which is 
 getting a little long, on a closely related issue which I find to be 
 important, but so rarely referred to that I had to come up with a name 
 for it - hijacking.
I'm just wondering what the NSA is making of this discussion :)
Hopefully, they'll analyze the site, get excited about D, and use D for their next generation software!
Aug 06 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Walter,

 Derek Parnell wrote:
 
 On Sun, 05 Aug 2007 11:47:18 -0700, Walter Bright wrote:
 
 I want to continue a bit in the Overloading/Inheritance thread which
 is getting a little long, on a closely related issue which I find to
 be important, but so rarely referred to that I had to come up with a
 name for it - hijacking.
 
I'm just wondering what the NSA is making of this discussion :)
Hopefully, they'll analyze the site, get excited about D, and use D for their next generation software!
Fat chance, most of D's advantages don't exist in under ~5000 LOC and anything over that and the NSA won't touch it. Besides there isn't 20+ years of best practices in how to right secure software in D (as this is in C) Sorry
Aug 07 2007
parent reply Sean Kelly <sean f4.ca> writes:
BCS wrote:
 Reply to Walter,
 
 Derek Parnell wrote:

 On Sun, 05 Aug 2007 11:47:18 -0700, Walter Bright wrote:

 I want to continue a bit in the Overloading/Inheritance thread which
 is getting a little long, on a closely related issue which I find to
 be important, but so rarely referred to that I had to come up with a
 name for it - hijacking.
I'm just wondering what the NSA is making of this discussion :)
Hopefully, they'll analyze the site, get excited about D, and use D for their next generation software!
Fat chance, most of D's advantages don't exist in under ~5000 LOC and anything over that and the NSA won't touch it. Besides there isn't 20+ years of best practices in how to right secure software in D (as this is in C)
I'd think DBC would be a perk, if nothing else. Assuming the NSA currently uses C, that is. Sean
Aug 07 2007
parent reply janderson <askme me.com> writes:
Sean Kelly wrote:
 BCS wrote:
 Reply to Walter,

 Derek Parnell wrote:

 On Sun, 05 Aug 2007 11:47:18 -0700, Walter Bright wrote:

 I want to continue a bit in the Overloading/Inheritance thread which
 is getting a little long, on a closely related issue which I find to
 be important, but so rarely referred to that I had to come up with a
 name for it - hijacking.
I'm just wondering what the NSA is making of this discussion :)
Hopefully, they'll analyze the site, get excited about D, and use D for their next generation software!
Fat chance, most of D's advantages don't exist in under ~5000 LOC and anything over that and the NSA won't touch it. Besides there isn't 20+ years of best practices in how to right secure software in D (as this is in C)
I'd think DBC would be a perk, if nothing else. Assuming the NSA currently uses C, that is. Sean
I thought NSA used ADA it was designed for such purposes. -Joel
Aug 07 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to janderson,

 Sean Kelly wrote:
 
 BCS wrote:
 
 Reply to Walter,
 
 Derek Parnell wrote:
 
 On Sun, 05 Aug 2007 11:47:18 -0700, Walter Bright wrote:
 
 I want to continue a bit in the Overloading/Inheritance thread
 which is getting a little long, on a closely related issue which
 I find to be important, but so rarely referred to that I had to
 come up with a name for it - hijacking.
 
I'm just wondering what the NSA is making of this discussion :)
Hopefully, they'll analyze the site, get excited about D, and use D for their next generation software!
Fat chance, most of D's advantages don't exist in under ~5000 LOC and anything over that and the NSA won't touch it. Besides there isn't 20+ years of best practices in how to right secure software in D (as this is in C)
I'd think DBC would be a perk, if nothing else. Assuming the NSA currently uses C, that is. Sean
I thought NSA used ADA it was designed for such purposes. -Joel
The only experience I have (yes I do have a tiny bit) is in C and is only about 500 loc.
Aug 07 2007
prev sibling parent Sean Kelly <sean f4.ca> writes:
janderson wrote:
 Sean Kelly wrote:
 BCS wrote:
 Fat chance, most of D's advantages don't exist in under ~5000 LOC and 
 anything over that and the NSA won't touch it. Besides there isn't 
 20+ years of best practices in how to right secure software in D (as 
 this is in C)
I'd think DBC would be a perk, if nothing else. Assuming the NSA currently uses C, that is.
I thought NSA used ADA it was designed for such purposes.
By my understanding, Ada was largely intended for robust systems control, while I would guess that much of the code written at the NSA is for in-house problem solving and that the safety provided by Ada isn't typically necessary. I think it's likely that the NSA most often uses mainstream languages for the bulk of its work, tending towards systems-oriented languages for their speed. Sean
Aug 08 2007
prev sibling parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
The old aliasing trick will still cause problems.

(The 'override' keyword won't solve the problem in the following case.)

   class A {
     void foo(int);
     void foo(long);
   }

   class B : A {
     alias A.foo foo;
     override void foo(int);
   }

   void bar(B b) {
     short val =3D 1;

     b.foo(val);  //calls 'foo(int)'
   }

Now 'foo(short)' is added to 'A':

   void bar(B b) {
     short val =3D 1;

     b.foo(val);  //calls 'foo(short)'
   }


Solutions:

(1) The aliasing trick will be banned (argh).

or

(2) One can overload final functions only (ermmm).

Or, to solve the hijacking problem once and for all:

(3) No implicit type casting with function calls.

Somehow (3) seems appealing (but I'm probably just too tired).
I go to sleep now... ;)




On Sun, 05 Aug 2007 21:47:18 +0300, Walter Bright  =

<newshound1 digitalmars.com> wrote:
 I want to continue a bit in the Overloading/Inheritance thread which i=
s =
 getting a little long, on a closely related issue which I find to be  =
 important, but so rarely referred to that I had to come up with a name=
=
 for it - hijacking.

 Hijacking is when code A depends on B, and then when seemingly unrelat=
ed =
 code C is modified, then A's behavior silently changes. Here's an  =
 example from C++:

 --A.h--
 void foo(long i);

 --B.c--
 #include "A.h"
 #include "C.h"
 ...
 foo(3);    // calls A's foo(long)
 --------

 Let's say A.h and C.h are developed by different people. In C.h, the  =
 developer adds:

 --C.h--
 void foo(int i);
 -----

 This does something completely different from A.h's foo(long), because=
=
 they just happened to share the same name. Now, when B.c is recompiled=
, =
 it's call to foo is silently *hijacked* by C.h's foo.

 Because of C++'s overloading rules and lack of modularity, there's no =
=
 way to programmatically defend against this. Instead, one has to rely =
on =
 coding conventions (such as using a unique package prefix name on all =
=
 symbols, like A_foo() and C_foo()).

 So how does this relate to the overloading/inheritance issues? Conside=
r:
 ----A.d----
 class A
 {
      ...
 }
 -----B.d----
 import A;
 class B : A
 {
      void foo(long);
 }
 ...
 void bar(B b)
 {
      b.foo(3);   // calls B.foo(long)
 }
 ----

 Let's say A.d comes from some third party library. Now the developer o=
f =
 A decides to add some functionality to class A, and adds the member  =
 function foo(int):

 ----A.d---
 class A
 {
      void foo(int);
 }
 ------------

 Now our hapless B programmer has his calls to B.foo(long) silently  =
 hijacked to A.foo(int) (under Java rules). I don't see any reasonable =
=
 way for B to defend against this. Certainly, developer A doesn't have =
=
 any idea who is deriving from A (and that's the point of polymorphism)=
- =
 but should he be disallowed from adding *any* method names? And the  =
 hapless B developer, he wrote class B years ago and no longer quite  =
 remembers how it works, he just recompiles it and now it silently fail=
s.
 So, this is one case where I feel C++ got it right, and Java didn't.

 (P.S. It's not a compiler implementation issue, nor is it a runtime  =
 performance issue.)
Aug 10 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Kristian Kilpi wrote:
 
 The old aliasing trick will still cause problems.
 
 (The 'override' keyword won't solve the problem in the following case.)
 
   class A {
     void foo(int);
     void foo(long);
   }
 
   class B : A {
     alias A.foo foo;
     override void foo(int);
   }
 
   void bar(B b) {
     short val = 1;
 
     b.foo(val);  //calls 'foo(int)'
   }
 
 Now 'foo(short)' is added to 'A':
 
   void bar(B b) {
     short val = 1;
 
     b.foo(val);  //calls 'foo(short)'
   }
I don't think this is a problem, because the B author explicitly and deliberately opened the door to this, therefore he is taking responsibility for it.
Aug 10 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Walter Bright wrote:
 Kristian Kilpi wrote:
 The old aliasing trick will still cause problems.

 (The 'override' keyword won't solve the problem in the following case.)

   class A {
     void foo(int);
     void foo(long);
   }

   class B : A {
     alias A.foo foo;
     override void foo(int);
   }

   void bar(B b) {
     short val = 1;

     b.foo(val);  //calls 'foo(int)'
   }

 Now 'foo(short)' is added to 'A':

   void bar(B b) {
     short val = 1;

     b.foo(val);  //calls 'foo(short)'
   }
I don't think this is a problem, because the B author explicitly and deliberately opened the door to this, therefore he is taking responsibility for it.
Yes and no. At the time the author wrote "alias A.foo foo;" they were allowing void foo(long), not void foo(short). Yes, they still "opened the door to this" because D's current behaviour is to pull all overloads past/present/future. Perhaps being able to specify overloads exactly would in some cases be of benefit, eg. alias A.foo(long) foo; Regan
Aug 11 2007
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Regan Heath wrote:
 Walter Bright wrote:
 Kristian Kilpi wrote:
 The old aliasing trick will still cause problems.

 (The 'override' keyword won't solve the problem in the following case.)

   class A {
     void foo(int);
     void foo(long);
   }

   class B : A {
     alias A.foo foo;
     override void foo(int);
   }

   void bar(B b) {
     short val = 1;

     b.foo(val);  //calls 'foo(int)'
   }

 Now 'foo(short)' is added to 'A':

   void bar(B b) {
     short val = 1;

     b.foo(val);  //calls 'foo(short)'
   }
I don't think this is a problem, because the B author explicitly and deliberately opened the door to this, therefore he is taking responsibility for it.
Yes and no. At the time the author wrote "alias A.foo foo;" they were allowing void foo(long), not void foo(short). Yes, they still "opened the door to this" because D's current behaviour is to pull all overloads past/present/future. Perhaps being able to specify overloads exactly would in some cases be of benefit, eg. alias A.foo(long) foo; Regan
Honestly, we need some ability to specify more of a function/method's signature in the general case anyhow. (Return type isn't really important, since it can't be different without at least one parameter difference) This would help with the super-aliasing case above, /and/ with the address operator. void foo (int); void foo (char[]); Currently: &foo => *(foo(int)) Proposed: &foo => *(foo(int)) or ambiguity error? &foo(int) => *(foo(int)) &foo(char[]) => *(foo(char[])) Currently: alias foo bar; // all foo's Proposed: alias foo bar; // all foo's alias foo(int) bar; // just this one alias foo(char[]) bar; // ditto The only thing that might get interesting is whether the compiler can easily distinguish (&foo()) as "take the address of a function foo with no params" versus "take the address of the result of function foo". (Is that even legal? Or useful?) -- Chris Nicholson-Sauls
Aug 11 2007