digitalmars.D - Why can't a method be virtual AND static at the same time?
- Martin Cejp (22/22) Jan 29 2014 This is a feature I've always missed in C++. Consider the code
- Vladimir Panteleev (28/51) Jan 29 2014 I don't understand this code. You have a "logger" local variable,
- Martin Cejp (9/67) Jan 29 2014 Oh no, these are supposed to be 2 independent usage examples, 1)
- Vladimir Panteleev (3/5) Jan 29 2014 Actually, there is: http://dlang.org/class.html#anonymous
- Tobias Pankrath (1/8) Jan 29 2014 Instead of defining it twice, you could alias the base version.
- Martin Cejp (8/17) Jan 29 2014 What do you mean? The methods have different signatures (static x
- Frustrated (58/81) Jan 29 2014 No, you are mixing concepts. Logger.print is a function that uses
- Martin Cejp (13/25) Jan 29 2014 Guess what: I DON'T CARE.
- Dicebot (1/1) Jan 29 2014 "Explicit better than implicit"
- Frustrated (4/32) Jan 29 2014 I don't care either. It's not that I don't disagree with you but
- ed (29/36) Jan 29 2014 On Wednesday, 29 January 2014 at 15:30:38 UTC, Martin Cejp wrote:
- Steven Schveighoffer (17/39) Jan 30 2014 Interface Logger {
- ed (15/21) Jan 30 2014 On Thursday, 30 January 2014 at 13:24:09 UTC, Steven
- Vitali (28/28) Jan 30 2014 Your motivation for this question is not clear. I can only guess.
This is a feature I've always missed in C++. Consider the code below: import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { static override void print(string msg) { writeln(msg); } } void main() { Logger logger = new ConsoleLogger; ConsoleLogger.print("Hello, World!"); } Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?
Jan 29 2014
On Wednesday, 29 January 2014 at 13:30:54 UTC, Martin Cejp wrote:This is a feature I've always missed in C++. Consider the code below: import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { static override void print(string msg) { writeln(msg); } } void main() { Logger logger = new ConsoleLogger; ConsoleLogger.print("Hello, World!"); }I don't understand this code. You have a "logger" local variable, but don't use it. Do you want the compiler to autodetect which local variable to use by selecting one in the current scope?Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?What are you trying to accomplish? You can use object instances as namespaces, too. Example: ///////////////////////////////////////////////////////// import std.stdio; interface Logger { void print(string msg); } class ConsoleLoggerImpl : Logger { override void print(string msg) const { writeln(msg); } } const ConsoleLogger = new ConsoleLoggerImpl; void main() { ConsoleLogger.print("Hello, World!"); } ///////////////////////////////////////////////////////// Note that ConsoleLogger is "instantiated" at compile time, not runtime. To instantiate it at runtime, during initialization, you can use a static constructor.
Jan 29 2014
On Wednesday, 29 January 2014 at 13:39:24 UTC, Vladimir Panteleev wrote:On Wednesday, 29 January 2014 at 13:30:54 UTC, Martin Cejp wrote:Oh no, these are supposed to be 2 independent usage examples, 1) being able to pass an instance of ConsoleLogger to a function/class expecting Logger and 2) being able to call a method without any instance at all.This is a feature I've always missed in C++. Consider the code below: import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { static override void print(string msg) { writeln(msg); } } void main() { Logger logger = new ConsoleLogger; ConsoleLogger.print("Hello, World!"); }I don't understand this code. You have a "logger" local variable, but don't use it. Do you want the compiler to autodetect which local variable to use by selecting one in the current scope?At compile time? Wow. Well, I guess this might work for me then :) (though there's no way around having to use 2 different names for the class and the const instance, is there?)Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?What are you trying to accomplish? You can use object instances as namespaces, too. Example: ///////////////////////////////////////////////////////// import std.stdio; interface Logger { void print(string msg); } class ConsoleLoggerImpl : Logger { override void print(string msg) const { writeln(msg); } } const ConsoleLogger = new ConsoleLoggerImpl; void main() { ConsoleLogger.print("Hello, World!"); } ///////////////////////////////////////////////////////// Note that ConsoleLogger is "instantiated" at compile time, not runtime. To instantiate it at runtime, during initialization, you can use a static constructor.
Jan 29 2014
On Wednesday, 29 January 2014 at 14:24:12 UTC, Martin Cejp wrote:(though there's no way around having to use 2 different names for the class and the const instance, is there?)Actually, there is: http://dlang.org/class.html#anonymous But I'm not sure if it works at module level.
Jan 29 2014
Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?Instead of defining it twice, you could alias the base version.
Jan 29 2014
On Wednesday, 29 January 2014 at 14:29:24 UTC, Tobias Pankrath wrote:What do you mean? The methods have different signatures (static x virtual) By the way, what I want to do is have a class LocalFileSystem that can both be passed as a FileSystem implementation and used directly, without instantiation (LocalFileSystem.openFile)Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?Instead of defining it twice, you could alias the base version.
Jan 29 2014
On Wednesday, 29 January 2014 at 13:30:54 UTC, Martin Cejp wrote:This is a feature I've always missed in C++. Consider the code below: import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { static override void print(string msg) { writeln(msg); } } void main() { Logger logger = new ConsoleLogger; ConsoleLogger.print("Hello, World!"); } Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?No, you are mixing concepts. Logger.print is a function that uses a vtable and takes a hidden parameter this. ConsoleLogger.print is a regular function that is not in a vtable(because it is static) and does not take a hidden parameter(again, because it is static). So, when you do ConsoleLogger.print how the heck would the compiler know which one you meant to use? While this might have a solution, in some cases in general a virtual method REQUIRES a virtual table and by using the keyword static on a function you are saying it is not part of the virtual table. Basically what you want is polymorphism here. Your two print functions are different. module main; import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { void print(string msg) { writeln(msg); } static void print2(string msg) { writeln(msg); } // Can we not rename print2 to print? } void main() { Logger logger = new ConsoleLogger; ConsoleLogger.print2("Hello, World!"); } works because you used a different name for print(print2) so there is no confusion. One could say that since you "access" print from the class(and not the object) that the compiler should use the static method instead of the virtual. This is actually different than saying print is both static and non-static(virtual), which is impossible. This all has to do with using the the same name of different things just like overriding methods do(they are actually different methods but use the same name because they have different definitions and generally can be deduced). It may be possible to do the same here. I don't know if there are any pitfalls. You would still need to implement the interface method print though, regardless. The real issue comes from cases like this though: module main; import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { void print(string msg) { writeln(msg); } static void print(string msg) { writeln(msg); } // assume this works } void main() { auto logger = new ConsoleLogger; logger.print("Hello, World!"); } Do you know the issue now? (Again, there might be ways around it but current that is not how the compiler thinks)
Jan 29 2014
On Wednesday, 29 January 2014 at 15:21:54 UTC, Frustrated wrote:No, you are mixing concepts. Logger.print is a function that uses a vtable and takes a hidden parameter this. ConsoleLogger.print is a regular function that is not in a vtable(because it is static) and does not take a hidden parameter(again, because it is static). So, when you do ConsoleLogger.print how the heck would the compiler know which one you meant to use? While this might have a solution, in some cases in general a virtual method REQUIRES a virtual table and by using the keyword static on a function you are saying it is not part of the virtual table.Guess what: I DON'T CARE. No really, I don't care at all about the implementation details. If you look at it from the purely semantic view, there's no ambiguity: got an instance? call the instance method. no instance? call the static one. Technically, yes, there would need to be two methods generated because of ABI differences, but this could be done behind the scenes. By making a method both override and static, you'd tell the compiler to do exactly that. Of course, the question is whether this would really be worth implementing and based on the reactions so far, I guess the answer is Not at all. I'm surprised that nobody else misses this feature, though.
Jan 29 2014
On Wednesday, 29 January 2014 at 15:30:38 UTC, Martin Cejp wrote:On Wednesday, 29 January 2014 at 15:21:54 UTC, Frustrated wrote:I don't care either. It's not that I don't disagree with you but I simply no longer care any more. I would care, and assuming such a thing mattered then I could care. I just don't any more....No, you are mixing concepts. Logger.print is a function that uses a vtable and takes a hidden parameter this. ConsoleLogger.print is a regular function that is not in a vtable(because it is static) and does not take a hidden parameter(again, because it is static). So, when you do ConsoleLogger.print how the heck would the compiler know which one you meant to use? While this might have a solution, in some cases in general a virtual method REQUIRES a virtual table and by using the keyword static on a function you are saying it is not part of the virtual table.Guess what: I DON'T CARE. No really, I don't care at all about the implementation details. If you look at it from the purely semantic view, there's no ambiguity: got an instance? call the instance method. no instance? call the static one. Technically, yes, there would need to be two methods generated because of ABI differences, but this could be done behind the scenes. By making a method both override and static, you'd tell the compiler to do exactly that. Of course, the question is whether this would really be worth implementing and based on the reactions so far, I guess the answer is Not at all. I'm surprised that nobody else misses this feature, though.
Jan 29 2014
On Wednesday, 29 January 2014 at 15:30:38 UTC, Martin Cejp wrote: You cannot override the static method because it isn't in the vtable and has a different calling convention; no this pointer is passed.Technically, yes, there would need to be two methods generated because of ABI differences, but this could be done behind the scenes. By making a method both override and static, you'd tell the compiler to do exactly that. Of course, the question is whether this would really be worth implementing and based on the reactions so far, I guess the answer is Not at all. I'm surprised that nobody else misses this feature, though.So you want to overload the static method. Well you can do that (untested but should work): --- class A { static void f() {writeln(__PRETTY_FUNCTION__);} } class B : A { void f() {writeln(__PRETTY_FUNCTION__);} } class C : B { // Overrides from B, overloads from A override void f() {writeln(__PRETTY_FUNCTION__);} } void main () { auto b= new B(); auto c = new C(); A.f(); b.f(); c.f(); } --- Is this what you're trying to do? IMO though overloading base class methods should be avoided Cheers, ed
Jan 29 2014
On Wed, 29 Jan 2014 08:30:53 -0500, Martin Cejp <minexew gmail.com> wrote:This is a feature I've always missed in C++. Consider the code below: import std.stdio; interface Logger { void print(string msg); } class ConsoleLogger : Logger { static override void print(string msg) { writeln(msg); } } void main() { Logger logger = new ConsoleLogger; ConsoleLogger.print("Hello, World!"); } Such definition of ConsoleLogger fails to compile. I don't see any drawbacks to allowing this though, except the compiler would probably have to generate 2 methods internally. The way it is now, you have to either define each method twice or always create an instance. Or am I missing an obvious solution?Interface Logger { final void print(string msg) { printImpl(msg); } void printImpl(string msg); } class ConsoleLogger : Logger { static void print(string msg) { writeln(msg); } override void printImpl(string msg) { print(msg); } } The issue you have is with the naming, you can't overload a virtual function with a static one. A static function call is a different call than a virtual one. You can't mix the two. -Steve
Jan 30 2014
On Thursday, 30 January 2014 at 13:24:09 UTC, Steven Schveighoffer wrote: [snip]The issue you have is with the naming, you can't overload a virtual function with a static one. A static function call is a different call than a virtual one. You can't mix the two. -SteveActually you can do this, see my other post. Overloading a static method with a virtual method or vice-versa works fine. You cannot do is override a static method because it isn't virtual and is nonsensical IMO. The OP said they expected overloading to occur in response to another post: [snip]What do you mean? The methods have different signatures (static x virtual)[snip] so I don't know why they were thinking to override, probably just a simple mistake. Cheers, ed
Jan 30 2014
Your motivation for this question is not clear. I can only guess. If you hope to get more performance by providing only one function, which is used as virtual and static at the same time, then this is impossible, because virtual functions are bound to a data instance by design. If you look for a possibility to type less code by skipping the instantiation of a class, then the use of an interface may be the wrong decision. If you want the virtual function to behave the same as the static function, then you can wrap the static function with the virtual one, like this: class ConsoleLogger : Logger { void print(string msg) { staticPrint(msg); } static void staticPrint(string msg) { writeln(msg); } } If you look for a possibility to override a static function like a virtual one, then you may be interested in so called "system mixins" (not part of D). System mixins are researched in aspect oriented programming (AOP). Read about it in this paper: Ichisugi, Y., Roudier, Y. (1998) Mixin Composition Strategies for the Modular Implementation of Aspect Weaving, Kyoto: Aspect Oriented Programming workshop at ICSE'98
Jan 30 2014