Re: Abstract functions in child classes

2011-12-05 Thread Christophe

FWIW, I agree with Addam. One of the things I like in D is that the 
langage is designed so that interpretations are made based on what you 
intend, and what you intend to do is checked. That is exactly what is 
done by using overwrite keyword. If you intend to make a non-abstract 
class, the compiler should check it is non-abstract and complain if it 
is not. This way, the error message pops where it belongs, i.e. at the 
class definition, not somewhere in another file where it is 
instanciated. It is not hard to add a specific unittest close to the 
class definition to test instanciation, but this is still much harder 
than writing 'abstract' at the beginning of the class definition when 
you intend to make it abstract (which is also much shorter than writing 
a sentence to indicate that the class is abstract in the documentation).

For special use-cases, when you don't know if the class is abstract or 
not because it is a template, you should just be allowed to write 
something like 'auto abstract' and the problem is solved.

Is is a really a larger pain to make this correction early to the 
langage, than to keep this little misfeature for years ? With an 
appropriate (and optional) warning to tell abstract class will soon have 
to be declared such for several years before there is an (optional) 
error, and maybe even a patch to make the correction automatically, that 
should not be such a pain.

-- 
Christophe


Re: Abstract functions in child classes

2011-12-05 Thread Steven Schveighoffer
On Fri, 02 Dec 2011 17:28:33 -0500, Jonathan M Davis jmdavisp...@gmx.com  
wrote:



On Friday, December 02, 2011 21:13:45 Adam wrote:

Anyway, I have my answer, and I know that D *does* have a reason for
this implicitism.


Okay. Maybe I've been skimming over this thread too much, but I don't
understand what forcing the programmer to mark an abstract class as  
abstract
would do. The compiler knows that the class is abstract regardless. It's  
going
to generate an error when you try and instantiate that class - whether  
or not
you mark the class as abstract or not has no impact on that as long as  
there

are abstract functions (the sole bizareness being able to mark a class as
abstract when none of its functions are abstract).


If I may describe what I see as the argument for (while trying to avoid a  
strawman), the benefit of requiring abstract is so the compilation of the  
class fails, not the isntantiation of the class.


It's feasible that someone could run tests that don't ever instantiate  
that exact class type, and then they wouldn't know it wasn't  
instantiable.  This is similar to someone who writes a library of  
templated objects, but doesn't test certain instantiations of them,  
finding out only later that it doesn't work.  I actually have been  
affected by this, since dcollections is all templates.  For example,  
containers of interfaces didn't work, but I didn't know until one of  
dcollections' users tried to do it.  Then I installed a workaround.


So to summarize, it's compiler error on declaration vs. compiler error on  
instantiation.  The question then becomes, given an expected concrete  
class, what is the probability that nobody tries to instantiate it during  
testing?  The worst case scenario is that the end-user's code doesn't  
compile.


The only thing that I see that marking the class abstract does is give  
the

programmer a visual indicator that the class is abstract. I do think that
that's valuable, and I'd love it if it were required when any functions  
in the
class are abstract and disallowed when none are, but I don't see how it  
can
have any effect on what errors you're getting. It's instatiating an  
abstract
class which as error, not declaring one, and unless you actually  
instantiate
it, there's no way for the compiler to catch it, because there's nothing  
to

catch.


This can be fixed via ddoc (which should know the class is abstract).

In fact, I think it does mark it as abstract in documentation (I know it  
marks interfaces as abstract unnecessarily).


-Steve


Re: Abstract functions in child classes

2011-12-02 Thread bearophile
mta`chrono Wrote:

 Even if the current behavior (what Adam mentioned) is not a bug, I think
 it seems to be a pitfall for std::programmer. The language/compiler
 should be more restrictive in this case.

If you think so, then write it in Bugzilla :-)

Bye,
bearophile


Re: Abstract functions in child classes

2011-12-02 Thread Steven Schveighoffer
On Fri, 02 Dec 2011 03:06:37 -0500, mta`chrono  
chr...@mta-international.net wrote:



Even if the current behavior (what Adam mentioned) is not a bug, I think
it seems to be a pitfall for std::programmer. The language/compiler
should be more restrictive in this case.


No, this is not a matter of allowing an invalid situation, the OP's code  
is perfectly viable and legal.  Here is a simpler example:


abstract class Parent
{
   abstract void foo();
}

class Child : Parent
{
   override void foo() {}
}

void main()
{
   Parent parent;

   parent = new Child();
}

why should it be disallowed to declare a variable of abstract type?  You  
aren't instantiating it.  It's the act of instantiation which is not and  
should not be allowed.


-Steve


Re: Abstract functions in child classes

2011-12-02 Thread Adam
To sort of put my two cents back in, and also to be one of those D
should be like Java! advocates, the problem is largely that a class
that inherits from an abstract and does *not* override some abstract
member becomes implicitly (to the user) abstract.

The way abstracts work in Java is that, in order to maintain that
child is an abstract (so that the actual implementation is
GrandChild), you must declare that both Child is an abstract class
and redeclare the function in question.

Now, perhaps there are good reasons in D for not requiring Child to
be declared abstract, but I'm not sure what they are. If a class
having any members that are abstract is implicitly abstract, then
the programmer should probably have to declare that the class is
abstract, as well.

The problem I ran into is that, until instantiation, the only way I
knew that Child was abstract would have been to go look at Parent
and see that I had forgotten to override a method.

Overall, the behavior seems unexpected (even if it's a personal
problem).


Re: Abstract functions in child classes

2011-12-02 Thread Steven Schveighoffer

On Fri, 02 Dec 2011 09:54:10 -0500, Adam a...@anizi.com wrote:


To sort of put my two cents back in, and also to be one of those D
should be like Java! advocates, the problem is largely that a class
that inherits from an abstract and does *not* override some abstract
member becomes implicitly (to the user) abstract.


Yes that is the state of affairs.



The way abstracts work in Java is that, in order to maintain that
child is an abstract (so that the actual implementation is
GrandChild), you must declare that both Child is an abstract class
and redeclare the function in question.


This appears superfluous to me.  A class is abstract either because you  
say it is, or because you haven't fully implemented all methods.


Your same line of thinking is used to promote mandatory overrides, which  
alerts you when something that was an override stops overriding or vice  
versa.  However, we aren't in the same place with abstract, since you  
*can* declare a class abstract even though all its methods are concrete.



Now, perhaps there are good reasons in D for not requiring Child to
be declared abstract, but I'm not sure what they are. If a class
having any members that are abstract is implicitly abstract, then
the programmer should probably have to declare that the class is
abstract, as well.

The problem I ran into is that, until instantiation, the only way I
knew that Child was abstract would have been to go look at Parent
and see that I had forgotten to override a method.


Exactly.  When you actually try to instantiate Child you find that it's  
abstract.  It's not a silent error (and is caught at compile time).


Now, I can see if you weren't expecting this, and you didn't test it, you  
may end up releasing code that is not what you wanted.  But what are the  
chances someone doesn't test their code before release?


In other words, we only gain from the compiler refusing to compile an  
abstract class not marked as 'abstract' if you don't instantiate it.  How  
often would this happen?



Overall, the behavior seems unexpected (even if it's a personal
problem).


It's unexpected, but caught at compile-time during development.  The error  
message is clear.  I see no reason to change things.


-Steve


Re: Abstract functions in child classes

2011-12-02 Thread Adam
I'm not sure how the fact that a class can be abstract with defined
functions impacts the case either way.

It's caught at compile time, but it requires explicitly testing that
any given time is or is not instantiable - how else would you test
for this particular case? It seems to be adding an additional test
case wherein for every abstract or implementation of abstract (or
supposed implementation of abstract, as is my case), you must test
for instantiability.

If you admit that the error is unexpected, but caught at compile-
time and only if you actually test for the specific case of if a
given implementation *is* instantiable, then you've clearly
demonstrated that the lack of a mandatory re-declaration of an
abstract results in an additional test case.

This *appears* to be at odds with a few of the other things I've
seen in D, which goes out of its way to ensure you do *not*
accidentally do things. In particular, I'm thinking of concurrency,
which does not even *allow* function-level synchronized declaration
(though it does allow synchronized blocks within functions) - it's
either at the class, or not at all.

To step back a bit, what is the *benefit* of not requiring a class
to be declared abstract if it does not override an abstract member?
It introduces implicit behavior and the potential for an additional
test case (in *what* sane world should I even HAVE to test that
something is instantiable?) for the sake of not typing 8 characters
in a Class definition


Re: Abstract functions in child classes

2011-12-02 Thread Jonathan M Davis
On Friday, December 02, 2011 14:54:10 Adam wrote:
 To sort of put my two cents back in, and also to be one of those D
 should be like Java! advocates, the problem is largely that a class
 that inherits from an abstract and does *not* override some abstract
 member becomes implicitly (to the user) abstract.
 
 The way abstracts work in Java is that, in order to maintain that
 child is an abstract (so that the actual implementation is
 GrandChild), you must declare that both Child is an abstract class
 and redeclare the function in question.
 
 Now, perhaps there are good reasons in D for not requiring Child to
 be declared abstract, but I'm not sure what they are. If a class
 having any members that are abstract is implicitly abstract, then
 the programmer should probably have to declare that the class is
 abstract, as well.
 
 The problem I ran into is that, until instantiation, the only way I
 knew that Child was abstract would have been to go look at Parent
 and see that I had forgotten to override a method.
 
 Overall, the behavior seems unexpected (even if it's a personal
 problem).

The class is abstract whether you mark it that way or not, because it has 
abstract methods. All marking the class as absract is going to do is give the 
programmer a visual clue that it's abstract. So, arguably, it really doesn't 
matter. Now, I personally think that it should be required if the class is 
abstract, since it's more consistent that way, but it's not going to have any 
effect on error messags are anything like that. From the compiler's 
perspective, there just isn't any need.

- Jonathan M Davis


Re: Abstract functions in child classes

2011-12-02 Thread Adam
Ok, let me give a more *specific* case of why this is a problem.

Suppose we have our Parent and Child cases from before

Parent exists in Library A
Child exists in my library, B
Library C, used by some developer, uses my library, B.

My Child is not meant to be abstract - it's intended to me
instantiable, and I document it as such. My documentation might even
include examples of construction.

I override all abstract methods of Parent.

Users of my library use instances of Child regularly.

Now, one day, the maintainer of Parent adds a new abstract function
to Parent. Please don't contest that this could happen - I see it
regularly in every language and every model of maintenance in real-
world development. Sometimes those interface developers are just
sadists.

Now, my library still compiles.

But, suddenly, users of my library are seeing errors on trying to
instantiate.

So what do I have to do to prevent this? I have to *explicitly*
check that Child is or is not instantiable, probably via unittest.
The alternative is that I must check over and read for every change
to the Parent library, even though the only reason I need to be
looking for new abstract functions is the exact same reason I'd need
to explicitly check that something is instantiable.


Re: Abstract functions in child classes

2011-12-02 Thread Andrej Mitrovic
How can you put out a library where you don't even test your classes?
That's just bad programming, period.


Re: Abstract functions in child classes

2011-12-02 Thread Adam
Ok, fine, let me put it THIS way.

Suppose I use a parent library, and *I* don't update it.

The USER of my library provides an updated version for some
unrelated reason.

So, NOT testing that something is instantiable or not - JUST that
it's instantiable - is bad programming...

...but requiring 8 characters to a class definition *is ok*?

So the only way to deal with this is *discipline*?

What you're telling me is that instead of requiring a class to be
explicitly abstract or not, it's instead a requirement of *good
programming* to test that something IS, in fact, ABSTRACT OR NOT?

What?


Re: Abstract functions in child classes

2011-12-02 Thread Regan Heath

On Fri, 02 Dec 2011 17:24:11 -, Adam a...@anizi.com wrote:


Ok, fine, let me put it THIS way.

Suppose I use a parent library, and *I* don't update it.

The USER of my library provides an updated version for some
unrelated reason.

So, NOT testing that something is instantiable or not - JUST that
it's instantiable - is bad programming...

...but requiring 8 characters to a class definition *is ok*?

So the only way to deal with this is *discipline*?

What you're telling me is that instead of requiring a class to be
explicitly abstract or not, it's instead a requirement of *good
programming* to test that something IS, in fact, ABSTRACT OR NOT?

What?


No-one is saying this, this is a strawman.  What has been said, is that  
if you were to distribute a library you should test it before releasing it.


R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Abstract functions in child classes

2011-12-02 Thread Adam
I grant you that I should test it, and I never said otherwise. If
I'm attacking a strawman, it's the same one that was just put in
front of me as a misinterpretation of my argument.
What I contest and addressed was a test for the sole purpose of
determining if my class, assumed to be non-abstract, was
instantiable or not.

Other tests being necessary for something to be good programming or
not, the issue here is that a test or a manual perusal of the base
class for changes (specifically, for the addition of new abstract
members) is required *just* to assert that my class is or is not
abstract.

Yes, I should test my class, but I shouldn't have to test it just to
ensure that it's the class I *intended* to create, rather than the
one the compiler assumes because of a base class change.


Re: Abstract functions in child classes

2011-12-02 Thread Adam
Or I provide it as source, in which case, D *can* check it.
But it means that when the parent is changed, my class type and
instantiability implicitly changes, too.


Re: Abstract functions in child classes

2011-12-02 Thread Regan Heath

On Fri, 02 Dec 2011 17:24:11 -, Adam a...@anizi.com wrote:

Ok, fine, let me put it THIS way.

Suppose I use a parent library, and *I* don't update it.

The USER of my library provides an updated version for some
unrelated reason.


So.. the user has:

Parent.dll
Your.dll
Their.exe

and everything is working ok.  Then they update Parent.dll to a new  
version.  And because D does not require 'abstract' on classes, it all  
breaks?


But.. Your.dll has not been recompiled.. so how is D supposed to detect  
this?


Or, were you suggesting the user supply a new Parent.dll to you, and you  
rebuild Your.dll with it?  In which case, when you run your unit tests you  
will get an error, right?


Regan

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Abstract functions in child classes

2011-12-02 Thread Regan Heath

On Fri, 02 Dec 2011 17:43:04 -, Adam a...@anizi.com wrote:


I grant you that I should test it, and I never said otherwise. If
I'm attacking a strawman, it's the same one that was just put in
front of me as a misinterpretation of my argument.


Well, I believe I understand your argument and I admit that I did find it  
odd that the error was not detected until the class was instantiated.   
But, once I thought about it I understood why this is the case, and I  
believe you understand it as well.  I also understand that you'd rather it  
wasn't the case.  I think the only area of disagreement here is how much  
of a problem this is likely to be.


Using the library example you gave, and assuming 'basic' testing of the  
exported classes etc, you would discover the problem immediately.  No harm  
done.  In most other cases, you're either the producer of the parent, or a  
consumer of the immediate child and you'll discover the problem  
immediately.  So, again no harm done.


The only remaining case (I can see) is the one I mentioned in my other  
thread/reply.  That of the end user swapping out the parent library, in  
which case your library is not recompiled and D can't help you here..  
unless it throws a runtime exception for this case.. hmm.


So.. adding abstract to the class definition doesn't seem to gain us  
much.  You can argue, as Jonathan did that it's more consistent, or  
provides a visual clue to the programmer.  But, the flip side is that it  
can be irritating to have to add it in the cases where it's already  
obvious to anyone reading the code - I have moments like that writing C#,  
even with good intelisense and good auto code generation.


Regan

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Abstract functions in child classes

2011-12-02 Thread Regan Heath

On Fri, 02 Dec 2011 17:44:44 -, Adam a...@anizi.com wrote:


Or I provide it as source, in which case, D *can* check it.
But it means that when the parent is changed, my class type and
instantiability implicitly changes, too.


True.  This is a case I hadn't considered before.  In this case the user  
will get an error instantiating your class and report a bug to you.  Not  
ideal, but assuming you document the versions of the parent library you're  
compatible with, and run your unit tests against these it shouldn't happen  
and when it does it will be because the user upgraded the parent library  
past your compatibility guarantee, so it's on them.


R

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Abstract functions in child classes

2011-12-02 Thread Adam
 Well, I believe I understand your argument and I admit that I did
find it
 odd that the error was not detected until the class was
instantiated.
 But, once I thought about it I understood why this is the case,
and I
 believe you understand it as well.  I also understand that you'd
rather it
 wasn't the case.  I think the only area of disagreement here is
how much
 of a problem this is likely to be.

 Using the library example you gave, and assuming 'basic' testing
of the
 exported classes etc, you would discover the problem immediately.
No harm
 done.  In most other cases, you're either the producer of the
parent, or a
 consumer of the immediate child and you'll discover the problem
 immediately.  So, again no harm done.

 The only remaining case (I can see) is the one I mentioned in my
other
 thread/reply.  That of the end user swapping out the parent
library, in
 which case your library is not recompiled and D can't help you
here..
 unless it throws a runtime exception for this case.. hmm.

 So.. adding abstract to the class definition doesn't seem to gain
us
 much.  You can argue, as Jonathan did that it's more consistent,
or
 provides a visual clue to the programmer.  But, the flip side is
that it
 can be irritating to have to add it in the cases where it's
already
 obvious to anyone reading the code - I have moments like that
writing C#,
 even with good intelisense and good auto code generation.

(I really need to get a client for this - I just had to manually
copy out your message and RegEx it to add the little  marks)

Well, specifically, here's what it *does* give you:
It means that a class *not* marked as abstract is not intended by
the programmer to be abstract (equivalent to explicitly marking
something as nonabstract). If we accept that the default class
declaration (class X {}) is non-abstract, then we probably don't
need to consider explicit specification of non-abstraction.
It means that a class *marked* as abstract is intended to be
abstract.

The difference is that the compiler can then decide at the
definition of a class - where this error belongs - if a Class
actually conforms to its contract of being abstract / concrete.

No harm is done if sufficient testing in place, but it still puts
the onus in *some* (probably quite specific or rare) circumstances
on the user of my class, because it's feasible for my class to have
been previously valid.

On the other hand, I should not require a unittest just to ensure
that my class is the same class it was between some (potentially
unknown) change. That's not to say that I shouldn't test, but I
shouldn't have to for this one, particular case.

But D does not allow me to explicitly make it clear that my class is
intended to be concrete, and it's relying on usage, rather than
definition, for this information.



Re: Abstract functions in child classes

2011-12-02 Thread Steven Schveighoffer

On Fri, 02 Dec 2011 11:05:00 -0500, Adam a...@anizi.com wrote:


I'm not sure how the fact that a class can be abstract with defined
functions impacts the case either way.

It's caught at compile time, but it requires explicitly testing that
any given time is or is not instantiable - how else would you test
for this particular case? It seems to be adding an additional test
case wherein for every abstract or implementation of abstract (or
supposed implementation of abstract, as is my case), you must test
for instantiability.


How do you run your normal tests without instantiating?  There is no need  
to test instantiability, since it's implicitly tested in your unit tests.



If you admit that the error is unexpected, but caught at compile-
time and only if you actually test for the specific case of if a
given implementation *is* instantiable, then you've clearly
demonstrated that the lack of a mandatory re-declaration of an
abstract results in an additional test case.


No.  It's covered by testing the functionality of the class.  You must  
instantiate to test anything related to the class.



To step back a bit, what is the *benefit* of not requiring a class
to be declared abstract if it does not override an abstract member?
It introduces implicit behavior and the potential for an additional
test case (in *what* sane world should I even HAVE to test that
something is instantiable?) for the sake of not typing 8 characters
in a Class definition


The benefit is, I don't have to declare something is abstract *twice*, I  
only have to do it by leaving the function unimplemented.  This does not  
stop you from putting abstract on the class if you want to add that extra  
documentation.  The doc generator probably can put whether the class is  
abstract directly in the docs anyway.


The burden of proving benefit is on *changing* the language, not leaving  
it the same.  What benefit is there to requiring it?  You already have to  
instantiate to test the class, or use it, so what is the risk of not  
letting the compiler imply it?


Contrary to something like function purity, which must be declared on the  
function signature for prototypes, you always know all the members of a  
class and its base classes.  There is no hidden information, and no chance  
the compiler could get it wrong.


-Steve


Re: Abstract functions in child classes

2011-12-02 Thread Adam
Your presumption is that someone is required to run tests just to
ensure that their class definition is what they expect. If I define
a class and it's concrete (because I've defined everything), and
later someone changes the parent class, my class is no longer
concrete (it no longer conforms to my intention, despite having no
way to actually *declare* my intentions in some explicit form). A
programmer should do testing, but may not (does D require a
programmer to test? No). You are implicitly testing the *definition*
of a class, rather than it's *use* (or accuracy, or stability, etc).

Testing or not testing is TANGENTIAL to the issue. Assume that
someone is not going to do unit test declarations (and do so without
running off on the wild notion that it's bad programming, because
we've already established that). WITHOUT that test, I cannot *know*
that my class *IS* what I originally defined it to be.

You mean you don't have to type 8 characters?

I've already given you the benefit of requiring it (or in another
argument, but I'm actually assuming you read the rest of this
thread). I shouldn't have to instantiate to test the DEFINITION of
my class. My class is concrete. Or, rather, it WAS concrete. Now
it's not. I have to test this? Unittests making use of an
instantiated case of my class will catch this, but what you're
saying is that, in the absence of a test case instantiating my
class, I have to go ahead and test the definition.

In other words, I've declared this class. At the time of declaring
it, it's concrete. Now I have to add a unittest to *ensure* it's
concrete for an instantiation of this - and all of this ignores my
previous posts and comments about USAGE of my class by others.

The compiler can't get it wrong, of course (and that's a ridiculous
notion, anyway), but it means that something can change implicitly
and transitively.


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 05:05 PM, Adam wrote:

To step back a bit, what is the *benefit* of not requiring a class
to be declared abstract if it does not override an abstract member?
It introduces implicit behavior and the potential for an additional
test case (in *what* sane world should I even HAVE to test that
something is instantiable?) for the sake of not typing 8 characters
in a Class definition


A second possible use case:

class C(T): T{
// some declarations
}

Now you really want that template to be instantiable with T being either 
an abstract or a concrete class. Anything else is bound to become 
extremely annoying.


Re: Abstract functions in child classes

2011-12-02 Thread Adam

 A second possible use case:

 class C(T): T{
  // some declarations
 }

 Now you really want that template to be instantiable with T being
either
 an abstract or a concrete class. Anything else is bound to become
 extremely annoying.

Could you expand on this case a bit? I'm not sure I follow the point
one way or another.


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 08:10 PM, Adam wrote:



A second possible use case:

class C(T): T{
  // some declarations
}



Now you really want that template to be instantiable with T being

either

an abstract or a concrete class. Anything else is bound to become
extremely annoying.


Could you expand on this case a bit? I'm not sure I follow the point
one way or another.


This is an useful pattern. I don't have a very useful example at hand, 
but this one should do. It does similar things that can be achieved with 
traits in Scala for example.



import std.stdio;
abstract class Cell(T){
abstract void set(T value);
abstract const(T) get();
private:
T field;
}

class AddSetter(C: Cell!T,T): C{
override void set(T value){field = value;}
}
class AddGetter(C: Cell!T,T): C{
override const(T) get(){return field;}
}

class DoubleCell(C: Cell!T,T): C{
override void set(T value){super.set(2*value);}
}

class OneUpCell(C: Cell!T,T): C{
override void set(T value){super.set(value+1);} 
}

class SetterLogger(C:Cell!T,T): C{
override void set(T value){
super.set(value);
writeln(cell has been set to ',value,'!);
}
}

class GetterLogger(C:Cell!T,T): C{
override const(T) get(){
auto value = super.get();
writeln(',value,' has been retrieved!);
return value;
}
}

class ConcreteCell(T): AddGetter!(AddSetter!(Cell!T)){}
class OneUpDoubleSetter(T): OneUpCell!(DoubleCell!(AddSetter!(Cell!T))){}
class DoubleOneUpSetter(T): DoubleCell!(OneUpCell!(AddSetter!(Cell!T))){}
void main(){
Cell!string x;
x = new ConcreteCell!string;
x.set(hello);
writeln(x.get());

Cell!int y;
y = new SetterLogger!(ConcreteCell!int);
y.set(123); // prints: cell has been set to '123'!

y = new GetterLogger!(DoubleCell!(ConcreteCell!int));
y.set(1234);
y.get(); // prints '2468' has been retrieved!

y = new AddGetter!(OneUpDoubleSetter!int);
y.set(100);
writeln(y.get()); // prints 202

y = new AddGetter!(DoubleOneUpSetter!int);
y.set(100);
writeln(y.get()); // prints 201

// ...
}


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 09:05 PM, Timon Gehr wrote:

On 12/02/2011 08:10 PM, Adam wrote:



A second possible use case:

class C(T): T{
// some declarations
}



Now you really want that template to be instantiable with T being

either

an abstract or a concrete class. Anything else is bound to become
extremely annoying.


Could you expand on this case a bit? I'm not sure I follow the point
one way or another.


This is an useful pattern. I don't have a very useful example at hand,
but this one should do. It does similar things that can be achieved with
traits in Scala for example.


import std.stdio;
abstract class Cell(T){
abstract void set(T value);
abstract const(T) get();
private:
T field;
}

class AddSetter(C: Cell!T,T): C{
override void set(T value){field = value;}
}
class AddGetter(C: Cell!T,T): C{
override const(T) get(){return field;}
}

class DoubleCell(C: Cell!T,T): C{
override void set(T value){super.set(2*value);}
}

class OneUpCell(C: Cell!T,T): C{
override void set(T value){super.set(value+1);}
}

class SetterLogger(C:Cell!T,T): C{
override void set(T value){
super.set(value);
writeln(cell has been set to ',value,'!);
}
}

class GetterLogger(C:Cell!T,T): C{
override const(T) get(){
auto value = super.get();
writeln(',value,' has been retrieved!);
return value;
}
}

class ConcreteCell(T): AddGetter!(AddSetter!(Cell!T)){}
class OneUpDoubleSetter(T): OneUpCell!(DoubleCell!(AddSetter!(Cell!T))){}
class DoubleOneUpSetter(T): DoubleCell!(OneUpCell!(AddSetter!(Cell!T))){}
void main(){
Cell!string x;
x = new ConcreteCell!string;
x.set(hello);
writeln(x.get());

Cell!int y;
y = new SetterLogger!(ConcreteCell!int);
y.set(123); // prints: cell has been set to '123'!

y = new GetterLogger!(DoubleCell!(ConcreteCell!int));
y.set(1234);
y.get(); // prints '2468' has been retrieved!

y = new AddGetter!(OneUpDoubleSetter!int);
y.set(100);
writeln(y.get()); // prints 202

y = new AddGetter!(DoubleOneUpSetter!int);
y.set(100);
writeln(y.get()); // prints 201

// ...
}


Oh, forgot to mention: This would not compile, if an explicit 'abstract' 
declaration on template class definitions was required.


Re: Abstract functions in child classes

2011-12-02 Thread Adam
So this pattern allows you to provide partial implementations of an
abstract, and use template specialization to provide a sort of
multiple inheritance rather than strict class definition /
extension. That's important in Scala because of the lack of multiple
inheritance (as I understand it).

Am I understanding this correctly - that the point of this approach is
to replicate composition by multiple inheritance?


Re: Abstract functions in child classes

2011-12-02 Thread Steven Schveighoffer

On Fri, 02 Dec 2011 14:06:00 -0500, Adam a...@anizi.com wrote:


Your presumption is that someone is required to run tests just to
ensure that their class definition is what they expect. If I define
a class and it's concrete (because I've defined everything), and
later someone changes the parent class, my class is no longer
concrete (it no longer conforms to my intention, despite having no
way to actually *declare* my intentions in some explicit form). A
programmer should do testing, but may not (does D require a
programmer to test? No). You are implicitly testing the *definition*
of a class, rather than it's *use* (or accuracy, or stability, etc).

Testing or not testing is TANGENTIAL to the issue. Assume that
someone is not going to do unit test declarations (and do so without
running off on the wild notion that it's bad programming, because
we've already established that). WITHOUT that test, I cannot *know*
that my class *IS* what I originally defined it to be.


You're being a bit dramatic, no?  The code didn't compile, the compiler  
caught it, and you have invented this theoretical case (which did *not*  
occur) to try and make your point.  I don't deny that requiring 'abstract'  
has some value, but what I question is how much is that value?  Since a  
reasonable developer uses tests (or uses the code in question himself) and  
will end up instantiating any concrete class during testing (or usage),  
I'd say the value is pretty close to zero (not zero, but very close).


But let's assume for a moment that it's standard practice to avoid unit  
testing.  The error that occurs is not a sneaky silent one, it is a loud  
compiler error.  The only risk is that the user of your library finds it  
before you do, because you didn't test, but it still doesn't compile.  Any  
time an error occurs at compile time, it is a win, since the user didn't  
accidentally use something incorrectly.  So here's the solution -- use  
tests.  In my opinion, breaking any existing code to add this requirement  
is unacceptable.


If the base class changes in any way, your derived class may not compile.   
It may break in subtle ways that *do* compile.  If you are going to insist  
on not testing your code after the base class changes, well, then I guess  
you will have to get used to it failing.  Just be thankful if you get a  
compiler error instead of a latent runtime error.


-Steve


Re: Abstract functions in child classes

2011-12-02 Thread Adam
 You're being a bit dramatic, no?  The code didn't compile, the
compiler
 caught it, and you have invented this theoretical case (which did
*not*
 occur) to try and make your point.  I don't deny that requiring
'abstract'
 has some value, but what I question is how much is that value?
Since a
 reasonable developer uses tests (or uses the code in question
himself) and
 will end up instantiating any concrete class during testing (or
usage),
 I'd say the value is pretty close to zero (not zero, but very
close).


A bit, but the point I've been trying to make is that it's an on-
instance usage, rather than a compile-time check (Timon Gehr has
since demonstrated a case as to why this could be valid), and the
response I keep getting back is you should be doing testing, when
my point is that I shouldn't be having to test the concreteness /
abstractness of a class. The theoretical case was to demonstrate
that this could be an issue. Is the value minimal? I'd argue
otherwise, but, that's probably tangential, so, moving on...

 But let's assume for a moment that it's standard practice to avoid
unit
 testing.  The error that occurs is not a sneaky silent one, it is
a loud
 compiler error.  The only risk is that the user of your library
finds it
 before you do, because you didn't test, but it still doesn't
compile.  Any
 time an error occurs at compile time, it is a win, since the user
didn't
 accidentally use something incorrectly.  So here's the solution --
use
 tests.  In my opinion, breaking any existing code to add this
requirement
 is unacceptable.

My issue here was (again, past tense because of Timon's example)
that the error occurs on usage rather than compilation, even when
that's quite outside of what I'd expect or want. It seemed to be at
odds with a lot of other D's semantic decisions, particularly with
respect to other transitive types and things liked synchronized, or
even shared (which I'd probably describe as closer to infectious
than transitive). What I've been asking is *why* this isn't a
requirement, and except for Timon, the only answers I'd gotten were
because it would break existing code (ok, but not an explanation
as to why it was DESIGNED that way in the first place), because it
was minimally inconvenient (even if more explicit, like other D
parts), or that to even raise the question just suggested I was a
bad programmer and that these sorts of definitions should be tested.

The crux of my issue with the testing argument is that, rather than
having the compiler be able to verify that a concrete class is, in
fact, concrete, I'm being asked to verify via unittest or otherwise
that my class is, in fact, concrete, rather than abstract. On a
related note, would you argue that there is any value to be gained
from *allowing* a class to be marked as concrete? That is,

concrete Child : Parent {}

*must* implement all abstract members? *I'd* use it, because if
nothing else, it provides a guarantee to users or inheritors of my
class as to its intended type (rather than using an implied
definition), even if the base type changes.

 If the base class changes in any way, your derived class may not
compile.
 It may break in subtle ways that *do* compile.  If you are going
to insist
 on not testing your code after the base class changes, well, then
I guess
 you will have to get used to it failing.  Just be thankful if you
get a
 compiler error instead of a latent runtime error.

And, again, my issue here is that the issue isn't caught until
instantiation, and is again relying on me to test the definition of
my class (rather than its usage). But, I'm going in circles, and I
just kept getting pointed back to the need to test my code (which
I've never contested). It just seemed particularly odd (and
insulting, given the actual statements) that the implication was
that I needed to test the abstractness or non-abstractness of my
code. Of *course* I'm going to test instantiation if I intend to
instantiate it, and of *course* I'd find it there, but my point was
never to ship anything untested to anyone. I just don't like having
this sort of assertion occur in a unittest rather than the actual
class definition (where, again, I think it belongs).

Somewhat related, but I know of companies that have separate
developers provide test cases than the implementers, and it's
perfectly possible (and valid) in D for the implementer to hand off
a finished definition of a concrete class only to discover its
problematic with respect to a unittest. Or, to relly stretch
pointless hypothetical arguments, in using some sort of dynamic
allocation of a class (Object.factory) rather than an explicit name
for my concrete class. Maybe using some sort of mechanism to auto-
generate unittests for any given implementation of an abstract,
rather than on an implementation-by-implementation basis.

Anyway, I have my answer, and I know that D *does* have a reason for
this implicitism.


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 09:27 PM, Adam wrote:

So this pattern allows you to provide partial implementations of an
abstract, and use template specialization to provide a sort of
multiple inheritance rather than strict class definition /
extension. That's important in Scala because of the lack of multiple
inheritance (as I understand it).

Am I understanding this correctly - that the point of this approach is
to replicate composition by multiple inheritance?


You can do that, but templates provide you with a lot more power. Note 
that some of my examples cannot be expressed as nicely in terms of 
multiple inheritance. That is because they rely on the order in which 
the classes are composed. This is sometimes discouraged in Scala afaik. 
I think, because there the type of an object does not depend on the 
trait mixin order. (not an issue here)


Parameterizing on the base class has quite some applications, its 
applications in C++ even have an own wikipedia page:


http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern


Re: Abstract functions in child classes

2011-12-02 Thread Steven Schveighoffer

On Fri, 02 Dec 2011 16:13:45 -0500, Adam a...@anizi.com wrote:


You're being a bit dramatic, no?  The code didn't compile, the

compiler

caught it, and you have invented this theoretical case (which did

*not*

occur) to try and make your point.  I don't deny that requiring

'abstract'

has some value, but what I question is how much is that value?

Since a

reasonable developer uses tests (or uses the code in question

himself) and

will end up instantiating any concrete class during testing (or

usage),

I'd say the value is pretty close to zero (not zero, but very

close).


A bit, but the point I've been trying to make is that it's an on-
instance usage, rather than a compile-time check (Timon Gehr has
since demonstrated a case as to why this could be valid), and the
response I keep getting back is you should be doing testing, when
my point is that I shouldn't be having to test the concreteness /
abstractness of a class. The theoretical case was to demonstrate
that this could be an issue. Is the value minimal? I'd argue
otherwise, but, that's probably tangential, so, moving on...


instantiation *is* done at compile-time.  The distinct difference is a  
compile-time error vs. a runtime exception.


In other words, it can't be used in the way you may have intended, but at  
least it doesn't *compile* in an invalid way



But let's assume for a moment that it's standard practice to avoid

unit

testing.  The error that occurs is not a sneaky silent one, it is

a loud

compiler error.  The only risk is that the user of your library

finds it

before you do, because you didn't test, but it still doesn't

compile.  Any

time an error occurs at compile time, it is a win, since the user

didn't

accidentally use something incorrectly.  So here's the solution --

use

tests.  In my opinion, breaking any existing code to add this

requirement

is unacceptable.


My issue here was (again, past tense because of Timon's example)
that the error occurs on usage rather than compilation, even when
that's quite outside of what I'd expect or want. It seemed to be at
odds with a lot of other D's semantic decisions, particularly with
respect to other transitive types and things liked synchronized, or
even shared (which I'd probably describe as closer to infectious
than transitive). What I've been asking is *why* this isn't a
requirement, and except for Timon, the only answers I'd gotten were
because it would break existing code (ok, but not an explanation
as to why it was DESIGNED that way in the first place), because it
was minimally inconvenient (even if more explicit, like other D
parts), or that to even raise the question just suggested I was a
bad programmer and that these sorts of definitions should be tested.


Why was it designed that way in the first place?  Probably because of C++  
legacy and/or early decisions by Walter.  This isn't a case of the current  
way is better than your way, it's a case of your way is only marginally  
better than the current way.  With D2 becoming closer to final, we have to  
have a very high bar for breaking existing code.



The crux of my issue with the testing argument is that, rather than
having the compiler be able to verify that a concrete class is, in
fact, concrete, I'm being asked to verify via unittest or otherwise
that my class is, in fact, concrete, rather than abstract.


The compiler does verify it's concrete on instantiation -- during compile  
time.


Again, this comes up next to never, and when it does, it's a compiler  
error, not a runtime error.  So no possibility of bad executable exists.



On a
related note, would you argue that there is any value to be gained
from *allowing* a class to be marked as concrete? That is,

concrete Child : Parent {}

*must* implement all abstract members? *I'd* use it, because if
nothing else, it provides a guarantee to users or inheritors of my
class as to its intended type (rather than using an implied
definition), even if the base type changes.


I probably wouldn't use it, because like abstract, it seems superfluous.   
I'd rather make my declaration by implementing or not implementing a  
method.  But that's just me.


-Steve


Re: Abstract functions in child classes

2011-12-02 Thread Jonathan M Davis
On Friday, December 02, 2011 21:13:45 Adam wrote:
 Anyway, I have my answer, and I know that D *does* have a reason for
 this implicitism.

Okay. Maybe I've been skimming over this thread too much, but I don't 
understand what forcing the programmer to mark an abstract class as abstract 
would do. The compiler knows that the class is abstract regardless. It's going 
to generate an error when you try and instantiate that class - whether or not 
you mark the class as abstract or not has no impact on that as long as there 
are abstract functions (the sole bizareness being able to mark a class as 
abstract when none of its functions are abstract).

It is perfectly legal and desirable to be able to have a class reference for 
an abstract class. e.g.

abstract class C
{
 abstract void func();
}

class D : C
{
 void func()
 {
 writeln(hello world);
 }
}

C c = new D();

The compiler has nothing to complain about with a reference to an abstract 
class until you try and instatiate it. So, how does explicitly marking the 
class abstract help with that?

I do think that it's a bit odd that D doesn't require that you mark classes as 
abstract if they have abstract functions and that it allows classes which 
don't have abstract functions to be marked abstract, but that should have no 
effect on whether the compiler can catch bugs related to abstract classes. The 
fact that the class has functions which are abstract is enough for the 
compiler to know that the class is abstract.

new C() is what needs to be disallowed for abstract classes, and that is an 
instantiation. It's the instantations that need to be checked, and they _are_ 
checked. It is a compilation error when you try and instantiate an abstract 
class.

The only thing that I see that marking the class abstract does is give the 
programmer a visual indicator that the class is abstract. I do think that 
that's valuable, and I'd love it if it were required when any functions in the 
class are abstract and disallowed when none are, but I don't see how it can 
have any effect on what errors you're getting. It's instatiating an abstract 
class which as error, not declaring one, and unless you actually instantiate 
it, there's no way for the compiler to catch it, because there's nothing to 
catch.

- Jonathan M Davis


Abstract functions in child classes

2011-12-01 Thread Adam
Ok, starting to feel like I'm missing something obvious...

The abstract keyword in the language reference states:
Functions declared as abstract can still have function bodies. This
is so that even though they must be overridden, they can still
provide �base class functionality.�

So, they must be overridden. Does the compiler do *anything* to
verify this for a child class?

This compiles:

import std.stdio;

public abstract class Parent {
public void hasDefinition() {
writeln(I have a definition);
}

public abstract void noDefinition();
}

public class Child : Parent {
public void unRelated() {
writeln(Unrelated);
}
}

void main() {
Child child;
}

However, if I change main() to:

void main() {
Parent instance = new Child();
}

I get cannot create instance of abstract class Child | function
noDefinition is abstract

Why is a reference / use of child in the context of a parent
required just to validate that the class is a valid extension of the
parent? More to the point, why does the first case even compile?


Re: Abstract functions in child classes

2011-12-01 Thread Regan Heath

On Thu, 01 Dec 2011 17:50:48 -, Adam a...@anizi.com wrote:

Ok, starting to feel like I'm missing something obvious...


This:

void main() {
Child child = new Child;
}

also produces the (expected) error.  Basically dmd was letting you get  
away with the abstract class because you never instantiated it.


Child child;

is just a reference to a Child class.

You could argue the compiler should error in either case, in fact, I  
would.  But perhaps there is a good generic programming reason not to...  
someone more experienced might be able to shed some light on it.


Regan

--
Using Opera's revolutionary email client: http://www.opera.com/mail/


Re: Abstract functions in child classes

2011-12-01 Thread Adam
I saw that a few minutes after posting as well, but if the only time
it's going to actually check the definition is if I instantiate it,
well... that's not so good for me if I'm writing implementations to be
used at a later date.

Hm. Guess we'll see. :)


Re: Abstract functions in child classes

2011-12-01 Thread Simen Kjærås

On Thu, 01 Dec 2011 18:50:48 +0100, Adam a...@anizi.com wrote:


Ok, starting to feel like I'm missing something obvious...

The abstract keyword in the language reference states:
Functions declared as abstract can still have function bodies. This
is so that even though they must be overridden, they can still
provide �base class functionality.�

So, they must be overridden. Does the compiler do *anything* to
verify this for a child class?

This compiles:

import std.stdio;

public abstract class Parent {
public void hasDefinition() {
writeln(I have a definition);
}

public abstract void noDefinition();
}

public class Child : Parent {
public void unRelated() {
writeln(Unrelated);
}
}

void main() {
Child child;
}

However, if I change main() to:

void main() {
Parent instance = new Child();
}

I get cannot create instance of abstract class Child | function
noDefinition is abstract

Why is a reference / use of child in the context of a parent
required just to validate that the class is a valid extension of the
parent? More to the point, why does the first case even compile?


Child is an abstract class because it has abstract methods. One of
these is the original hasDefinition, the other is noDefinition. Child
itself is under no obligation to override them, because there could be
a class GrandChild : Child, which does override them.

Declaring a variable of type Child, where Child is abstract class,
should of course not be an error. That child could be either a Son or
a Daughter (or a transvestite child, I guess, but let's not get too
carried away), both of whom override these abstract methods.

That said, it would be a lot clearer if the language gave an error
when a class with abstract methods is not marked abstract.


Re: Abstract functions in child classes

2011-12-01 Thread Steven Schveighoffer
On Thu, 01 Dec 2011 12:58:24 -0500, Regan Heath re...@netmail.co.nz  
wrote:



On Thu, 01 Dec 2011 17:50:48 -, Adam a...@anizi.com wrote:

Ok, starting to feel like I'm missing something obvious...


This:

 void main() {
 Child child = new Child;
 }

also produces the (expected) error.  Basically dmd was letting you get  
away with the abstract class because you never instantiated it.


Child child;

is just a reference to a Child class.

You could argue the compiler should error in either case, in fact, I  
would.  But perhaps there is a good generic programming reason not to...  
someone more experienced might be able to shed some light on it.


A Child reference could be for a further derived GrandChild type that does  
actually implement the required functions.  In fact, Child is also  
abstract, it just isn't required to be marked as such.


All marking a class as abstract does is make it uninstantiable, just like  
having an abstract method does.  However, you can mark a class abstract to  
prevent it from being instantiated, even when none of its methods are  
abstract (could be useful in some situations).


However, I have no idea why you'd mark a concrete function as abstract.   
That seems like a just because we could feature.


-Steve


Re: Abstract functions in child classes

2011-12-01 Thread Adam
I can see the case for a grand-child, but if a class does not provide
a definition for an abstract member, is that class not, by
association, abstract?

Classes become abstract if they are defined within an abstract
attribute, or if any of the virtual member functions within it are
declared as abstract.

I *assume* that by extending Parent, Child inherits the abstract
function. If inheriting an abstract member transitively makes Child an
abstract, then I find that the abstract keyword at the class level is
little more than explicit documentation.


Re: Abstract functions in child classes

2011-12-01 Thread Adam
Because the function in this case has no definition in the base
abstract class (Parent), but is referenced / called by Parent's
members. I did not want Parent to provide a default definition for the
function precisely because a large point of the abstract was that
method.


Re: Abstract functions in child classes

2011-12-01 Thread Simen Kjærås

On Thu, 01 Dec 2011 19:19:49 +0100, Adam a...@anizi.com wrote:


I can see the case for a grand-child, but if a class does not provide
a definition for an abstract member, is that class not, by
association, abstract?


Of course. That's what I said. Or meant, at any rate.



Classes become abstract if they are defined within an abstract
attribute, or if any of the virtual member functions within it are
declared as abstract.

I *assume* that by extending Parent, Child inherits the abstract
function. If inheriting an abstract member transitively makes Child an
abstract, then I find that the abstract keyword at the class level is
little more than explicit documentation.


Indeed. But I'm not one to argue that explicit documentation is bad.


Re: Abstract functions in child classes

2011-12-01 Thread Jacob Carlborg

On 2011-12-01 19:18, Steven Schveighoffer wrote:

On Thu, 01 Dec 2011 12:58:24 -0500, Regan Heath re...@netmail.co.nz
wrote:


On Thu, 01 Dec 2011 17:50:48 -, Adam a...@anizi.com wrote:

Ok, starting to feel like I'm missing something obvious...


This:

void main() {
Child child = new Child;
}

also produces the (expected) error. Basically dmd was letting you get
away with the abstract class because you never instantiated it.

Child child;

is just a reference to a Child class.

You could argue the compiler should error in either case, in fact, I
would. But perhaps there is a good generic programming reason not
to... someone more experienced might be able to shed some light on it.


A Child reference could be for a further derived GrandChild type that
does actually implement the required functions. In fact, Child is also
abstract, it just isn't required to be marked as such.

All marking a class as abstract does is make it uninstantiable, just
like having an abstract method does. However, you can mark a class
abstract to prevent it from being instantiated, even when none of its
methods are abstract (could be useful in some situations).

However, I have no idea why you'd mark a concrete function as abstract.
That seems like a just because we could feature.

-Steve


The method in the super class could provide a partial implementation 
that sub class can call. But that might be better divided in two methods.


--
/Jacob Carlborg


Re: Abstract functions in child classes

2011-12-01 Thread Jacob Carlborg

On 2011-12-01 19:14, Simen Kjærås wrote:

On Thu, 01 Dec 2011 18:50:48 +0100, Adam a...@anizi.com wrote:


Ok, starting to feel like I'm missing something obvious...

The abstract keyword in the language reference states:
Functions declared as abstract can still have function bodies. This
is so that even though they must be overridden, they can still
provide �base class functionality.�

So, they must be overridden. Does the compiler do *anything* to
verify this for a child class?

This compiles:

import std.stdio;

public abstract class Parent {
public void hasDefinition() {
writeln(I have a definition);
}

public abstract void noDefinition();
}

public class Child : Parent {
public void unRelated() {
writeln(Unrelated);
}
}

void main() {
Child child;
}

However, if I change main() to:

void main() {
Parent instance = new Child();
}

I get cannot create instance of abstract class Child | function
noDefinition is abstract

Why is a reference / use of child in the context of a parent
required just to validate that the class is a valid extension of the
parent? More to the point, why does the first case even compile?


Child is an abstract class because it has abstract methods. One of
these is the original hasDefinition, the other is noDefinition. Child
itself is under no obligation to override them, because there could be
a class GrandChild : Child, which does override them.

Declaring a variable of type Child, where Child is abstract class,
should of course not be an error. That child could be either a Son or
a Daughter (or a transvestite child, I guess, but let's not get too
carried away), both of whom override these abstract methods.

That said, it would be a lot clearer if the language gave an error
when a class with abstract methods is not marked abstract.


There's also the possibility to have the declarations in one object file 
and the implementation in another, if I recall correctly. This allows to 
use a .di and .d file, similar to .c and .h in C/C++.


--
/Jacob Carlborg