www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - unimplemented abstract function compiles.

reply Eric <noreply null.com> writes:
Code below compiles while I would not expect it to compile.
Is there a reason that this compiles?

Specs are a bit lite on abstract classes.
Only thing I found that would need to allow this is: "19.4 
functions without bodies" 
https://dlang.org/spec/function.html#function-declarations
But that's explicitly without the abstract keyword..


class I {
   abstract void f();
}

class C : I {
}

unittest {
   C c = cast(C) Object.factory("C");
   c.f();
}


I also couldn't find anything about this in the issue tracker.
Aug 11 2018
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 12/08/2018 8:55 AM, Eric wrote:
 Code below compiles while I would not expect it to compile.
 Is there a reason that this compiles?
 
 Specs are a bit lite on abstract classes.
 Only thing I found that would need to allow this is: "19.4 functions 
 without bodies" https://dlang.org/spec/function.html#function-declarations
 But that's explicitly without the abstract keyword..
 
 
 class I {
    abstract void f();
 }
 
 class C : I {
 }
 
 unittest {
    C c = cast(C) Object.factory("C");
    c.f();
 }
 
 
 I also couldn't find anything about this in the issue tracker.
No bug. You forgot to throw -unittest when you compiled. /tmp/dmd_run2hTpLG(_D4core7runtime18runModuleUnitTestsUZ19unittestSegvHandlerUNbiPSQCk3sys5posix6signal9siginfo_tPvZv+0x38)[0x55d9bba94a40] /lib/x86_64-linux-gnu/libpthread.so.0(+0x13150)[0x7f970a253150] /tmp/dmd_run2hTpLG(_D9onlineapp17__unittest_L14_C1FZv+0x3a)[0x55d9bba8fe6e] /tmp/dmd_run2hTpLG(_D9onlineapp9__modtestFZv+0x9)[0x55d9bba8fe81] /tmp/dmd_run2hTpLG(_D4core7runtime18runModuleUnitTestsUZ14__foreachbody2MFPS6object10ModuleInfoZi+0x38)[0x55d9bba94a94] /tmp/dmd_run2hTpLG(_D6object10ModuleInfo7opApplyFMDFPSQBhQBdZiZ9__lambda2MFyPSQCfQCbZi+0x23)[0x55d9bba9098f] /tmp/dmd_run2hTpLG(_D2rt5minfo17moduleinfos_applyFMDFyPS6object10ModuleInfoZiZ14__foreachbody2MFKSQCz19sections_elf_shared3DSOZi+0x56)[0x55d9bba921ae] /tmp/dmd_run2hTpLG(_D2rt19sections_elf_shared3DSO7opApplyFMDFKSQBqQBqQyZiZi+0x45)[0x55d9bba9223d] /tmp/dmd_run2hTpLG(_D2rt5minfo17moduleinfos_applyFMDFyPS6object10ModuleInfoZiZi+0x22)[0x55d9bba9213a] /tmp/dmd_run2hTpLG(_D6object10ModuleInfo7opApplyFMDFPSQBhQBdZiZi+0x22)[0x55d9bba90966] /tmp/dmd_run2hTpLG(runModuleUnitTests+0x13e)[0x55d9bba9486a] /tmp/dmd_run2hTpLG(_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZv+0x25)[0x55d9bba90f31] /tmp/dmd_run2hTpLG(_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv+0x20)[0x55d9bba90eb8] /tmp/dmd_run2hTpLG(_d_run_main+0x1cf)[0x55d9bba90e23] /tmp/dmd_run2hTpLG(main+0x22)[0x55d9bba8fea6] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f9709a621c1] /tmp/dmd_run2hTpLG(_start+0x2a)[0x55d9bba8fd4a] Error: program killed by signal 11
Aug 11 2018
parent reply ag0aep6g <anonymous example.com> writes:
On 08/11/2018 11:20 PM, rikki cattermole wrote:
 On 12/08/2018 8:55 AM, Eric wrote:
 Code below compiles while I would not expect it to compile.
 Is there a reason that this compiles?
[...]
 No bug. You forgot to throw -unittest when you compiled.
[...]
 Error: program killed by signal 11
If that's DMD segfaulting, that's definitely a bug. If that's not DMD segfaulting, you're running the program which Eric expects not to compile. So there might be a bug (or Eric's expectation is wrong).
Aug 11 2018
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 12/08/2018 11:12 AM, ag0aep6g wrote:
 On 08/11/2018 11:20 PM, rikki cattermole wrote:
 On 12/08/2018 8:55 AM, Eric wrote:
 Code below compiles while I would not expect it to compile.
 Is there a reason that this compiles?
[...]
 No bug. You forgot to throw -unittest when you compiled.
[...]
 Error: program killed by signal 11
If that's DMD segfaulting, that's definitely a bug. If that's not DMD segfaulting, you're running the program which Eric expects not to compile. So there might be a bug (or Eric's expectation is wrong).
Eric's is wrong. abstract on a method essentially acts as extern except for class methods. Because we're dealing with classes, it won't be hit until runtime. Its weird, but at each stage it all kinda makes sense.
Aug 11 2018
prev sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Saturday, 11 August 2018 at 23:12:43 UTC, ag0aep6g wrote:
 On 08/11/2018 11:20 PM, rikki cattermole wrote:
 On 12/08/2018 8:55 AM, Eric wrote:
 Code below compiles while I would not expect it to compile.
 Is there a reason that this compiles?
[...]
 No bug. You forgot to throw -unittest when you compiled.
[...]
 Error: program killed by signal 11
If that's DMD segfaulting, that's definitely a bug.
its not
/tmp/dmd_run2hTpLG(_D9onlineapp17__unittest_L14_C1FZv+0x3a)[0x55d9bba8fe6e]
/tmp/dmd_run2hTpLG(_D9onlineapp9__modtestFZv+0x9)[0x55d9bba8fe81]
That is run.dlang.io running the resulting executable. (I know because I've looked a way too many dmd segfaults ;) )
 If that's not DMD segfaulting, you're running the program which 
 Eric expects not to compile. So there might be a bug (or Eric's 
 expectation is wrong).
Aug 11 2018
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
On 08/11/2018 10:55 PM, Eric wrote:
 Code below compiles while I would not expect it to compile.
 Is there a reason that this compiles?
 
[...]
 
 class I {
    abstract void f();
 }
 
 class C : I {
 }
 
 unittest {
    C c = cast(C) Object.factory("C");
    c.f();
 }
Not a bug, as far as I see. You don't get compile-time errors with Object.factory. It works at run time, on dynamic values (e.g., a class name entered on the command line). You're calling it with a constant string, but the compiler doesn't care about that. There's no special handling for that. Object.factory returns `null` when it can't create the object. And it does that in your example, because of the abstract method (and because "C" is wrong; the name must be fully qualified). You're supposed to check for `null` before attempting to use the object. If you want a compile-time check, don't use Object.factory. Use `new` instead: C c = new C; /* Error: cannot create instance of abstract class C */
Aug 11 2018
parent reply Eric <noreply null.com> writes:
I thought it would work the same way as an interface (which must 
be implemented by the direct sub class, otherwise compile error).
But apparently it's possible to implement an abstract function 
anywhere in the class hierarchy. That makes it, in this case, 
impossible to check during compile time.

I ran into this while loading objects from a file using 
Object.factory and forgot to implement an abstract function in 
one class.
Aug 12 2018
next sibling parent ag0aep6g <anonymous example.com> writes:
On 08/12/2018 07:29 PM, Eric wrote:
 I thought it would work the same way as an interface (which must be 
 implemented by the direct sub class, otherwise compile error).
From the spec text [1], I'd also expect an error. It says: "An abstract member function must be overridden by a derived class." And later: "Classes become abstract if any of its virtual member functions are *declared* abstract or if they are defined within an abstract attribute" (emphasis mine). So, arguably, DMD shouldn't accept your `C` class as abstract. It's not marked as abstract itself, and it doesn't have a declaration of an abstract method either. But in cases like this it's more likely that the spec will be changed to reflect what DMD does than DMD getting changed to break existing code.
 But apparently it's possible to implement an abstract function anywhere 
 in the class hierarchy. That makes it, in this case, impossible to check 
 during compile time.
You can check it at compile time. The compiler just doesn't do it for you proactively. `C` is an abstract class, just like `I` is, and there's a trait for that [2]: static assert(!__traits(isAbstractClass, C)); For nicer syntax, there's also a wrapper around it in std.traits [3]: import std.traits: isAbstractClass; static assert(!isAbstractClass!C); If you want to make sure that your class isn't accidentally abstract, you can add an assert like that. [1] https://dlang.org/spec/attribute.html#abstract [2] https://dlang.org/spec/traits.html#isAbstractClass [3] https://dlang.org/phobos/std_traits.html#isAbstractClass
Aug 12 2018
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2018-08-12 19:29, Eric wrote:
 I thought it would work the same way as an interface (which must be 
 implemented by the direct sub class, otherwise compile error).
 But apparently it's possible to implement an abstract function anywhere 
 in the class hierarchy. That makes it, in this case, impossible to check 
 during compile time.
It will be checked during compile time if the class is referenced during compile time. In your example it's not. The thing is that a library can provide an abstract class which is then subclassed and completely implemented by the user of the library. In that case you don't want an compile error when you're compiling the library but now using the class. One can argue that an abstract class always should be marked with "abstract" but that's not currently how the language is working. -- /Jacob Carlborg
Aug 13 2018