Abstract functions in child classes

Steven Schveighoffer schveiguy at yahoo.com
Fri Dec 2 13:46:52 PST 2011


On Fri, 02 Dec 2011 16:13:45 -0500, Adam <Adam at 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


More information about the Digitalmars-d-learn mailing list