digitalmars.D - Package functions cannot be abstract?!
- Jonathan Levi (17/17) Jan 29 2019 Why in the world can abstract functions not be only visible to
- Neia Neutuladh (25/27) Jan 29 2019 `package`-protected functions are not overridable. Only functions that a...
- Marco de Wild (56/58) Jan 29 2019 If you could make a package-private function abstract, that would
- Benjamin Schaaf (14/16) Jan 30 2019 So you want a public class that has private abstract methods that
- Neia Neutuladh (8/13) Jan 30 2019 The reason you use package instead of protected is to expose the functio...
- Neia Neutuladh (27/43) Jan 30 2019 To clarify: it's not a great decision in Java either; you can access
- Jonathan M Davis (25/29) Jan 31 2019 It does seem weird when you first encounter, it but it's a feature that'...
- Jonathan M Davis (9/26) Jan 30 2019 By design, only public and protected functions are virtual. private and
- Jonathan Levi (7/7) Jan 31 2019 Okay thanks,
Why in the world can abstract functions not be only visible to only a package? I have a public abstract class which has private implementations. Some abstract member functions are needed for use withing the package but should not be visible publicly. What is the point of making this not possible?! Is it more difficult to implement or is just a random limitation for the heck of it? Do you have a recommendation on how to do what I am trying to do? Thanks. ``` class Cls { package abstract void fun(string a){}; } ``` Error: function `onlineapp.A.a` package functions cannot be abstract
Jan 29 2019
On Wed, 30 Jan 2019 04:05:15 +0000, Jonathan Levi wrote:Why in the world can abstract functions not be only visible to only a package?`package`-protected functions are not overridable. Only functions that are visible to all derived classes can be overridden. This is in the spec: https://dlang.org/spec/function.html#virtual-functions "Member functions which are private or package are never virtual, and hence cannot be overridden." This seems pretty weird on reflection. Visibility and virtual dispatch seem orthogonal. To make your thing work, I'd write a package function that forwards to a protected function: class Cls { package void fun(string a) { return funImpl(a); } protected abstract void funImpl(string a); } This isn't exactly the same; a subtype in a different package could override this function, which might be undesirable. As a workaround: package struct Hidden {} class Cls { package void fun(string a) { return funImpl(a, Hidden.init); } protected abstract void funImpl(string a, Hidden h); } For a subclass in a different package to override funImpl, it would have to access Hidden, which it shouldn't be able to do.
Jan 29 2019
On Wednesday, 30 January 2019 at 04:05:15 UTC, Jonathan Levi wrote:Why in the world can abstract functions not be only visible to only a package?If you could make a package-private function abstract, that would imply that implementations outside of the package are never functional. In foo/x.d: --- module foo.x; public abstract class X { package abstract doThings(); } public void letsDo(X x) { x.doThings(); } --- In bar/y.d: --- module bar.y; import foo.x; public class Y : X { // Does not know that doThings() needs to be implemented. } void demo() { letsDo(new Y()); } --- This will give a runtime error, as y.do() is called without being implemented. Depending on your exact problem, you could: - Make X package private. - Make doThings() protected. - Make derived classes of X final. - Expose methods publicly that take X as an input parameter. I.e.: module foo.x; package abstract class X { protected abstract void doThings(); } public class XImpl : X { protected override void doThings() { import std.stdio; writeln("Hello world"); } } public void letsDo(X x) { x.doThings(); } --- In bar/y.d: --- module bar.y; import foo.x; void demo() { letsDo(new XImpl()); } ---
Jan 29 2019
On Wednesday, 30 January 2019 at 04:05:15 UTC, Jonathan Levi wrote:Do you have a recommendation on how to do what I am trying to do?So you want a public class that has private abstract methods that you share across private implementations. Why not use an interface? interface F { void foo(); } private abstract class Base : F { abstract void bar() { ... } } class Impl : Base { ... }
Jan 30 2019
On Wed, 30 Jan 2019 12:28:42 +0000, Benjamin Schaaf wrote:On Wednesday, 30 January 2019 at 04:05:15 UTC, Jonathan Levi wrote:The reason you use package instead of protected is to expose the function to be called by other functions in different modules in the same package. It feels to me like D took some design cues here from Java and C++ without accounting for differences between D's `private` and Java's, then rolled those decisions forward into `package`. Virtual dispatch and protection should be orthogonal except insofar as the compiler can use protection to prove that there are no overrides of a function.Do you have a recommendation on how to do what I am trying to do?So you want a public class that has private abstract methods that you share across private implementations. Why not use an interface?
Jan 30 2019
On Wed, 30 Jan 2019 17:21:31 +0000, Neia Neutuladh wrote:On Wed, 30 Jan 2019 12:28:42 +0000, Benjamin Schaaf wrote:To clarify: it's not a great decision in Java either; you can access private members of other classes defined in a mutual scope. (Nested classes can access anything their parent classes can access, and a class can access anything its nested classes can access.) But Java discourages you from writing this kind of code in the first place, while D is much more keen on modules with multiple declarations, and those declarations expose their private members to each other. So it would make perfect sense to write something like: --- module foo; class A { /*virtual*/ private int stuff() { return 1; } } class B : A { override private int stuff() { return 2; } } --- But because Java didn't make `private` and `virtual` orthogonal like they could and probably should be, D doesn't either. And because of D's module system, the problem is much more visible in D. I didn't realize that C++ allows private virtual functions. With C++, a private virtual function is overridable by derived classes, even if they aren't friends. This prevents the child classes from calling the function despite having defined it. Which is weird.On Wednesday, 30 January 2019 at 04:05:15 UTC, Jonathan Levi wrote:The reason you use package instead of protected is to expose the function to be called by other functions in different modules in the same package. It feels to me like D took some design cues here from Java and C++ without accounting for differences between D's `private` and Java's, then rolled those decisions forward into `package`. Virtual dispatch and protection should be orthogonal except insofar as the compiler can use protection to prove that there are no overrides of a function.Do you have a recommendation on how to do what I am trying to do?So you want a public class that has private abstract methods that you share across private implementations. Why not use an interface?
Jan 30 2019
On Wednesday, January 30, 2019 10:31:45 AM MST Neia Neutuladh via Digitalmars-d wrote:I didn't realize that C++ allows private virtual functions. With C++, a private virtual function is overridable by derived classes, even if they aren't friends. This prevents the child classes from calling the function despite having defined it. Which is weird.It does seem weird when you first encounter, it but it's a feature that's actually quite useful with NVI (Non-Virtual Inheritance). It makes it possible to override a function's behavior while still guaranteeing that the function is only called in a certain way. A classic way to use it would be to have a non-virtual, public function in the base class which runs code before and/or after calling the private, virtual function. Now, you can do the same thing without having virtual, private functions. You just can't prevent anyone from calling the function elsewhere. So, arguably, you can't prevent a particular class of bugs, but it's probably not something that's a big deal in practice. IIRC, TDPL talks about doing NVI in D with interfaces, but whatever it said exactly doesn't work right now and probably never will. D's approach of tying whether a function is virtual or not to its access level prevents certain classes of problems and generally simplifies things, so it's arguably a win overall, but there's no question that there are some idioms that it makes impossible. Whether those idioms would be worth complicating the language in order to have is debatable, but for better or worse, I would not expect D to change how it handles which functions are virtual. The main fallout of that is that occasionally, you might have a function which you have to make public or protected in order to be virtual when you'd prefer for it to be package or private. The vast majority of the time, however, it's a non-issue. - Jonathan M Davis
Jan 31 2019
On Tuesday, January 29, 2019 9:05:15 PM MST Jonathan Levi via Digitalmars-d wrote:Why in the world can abstract functions not be only visible to only a package? I have a public abstract class which has private implementations. Some abstract member functions are needed for use withing the package but should not be visible publicly. What is the point of making this not possible?! Is it more difficult to implement or is just a random limitation for the heck of it? Do you have a recommendation on how to do what I am trying to do? Thanks. ``` class Cls { package abstract void fun(string a){}; } ``` Error: function `onlineapp.A.a` package functions cannot be abstractBy design, only public and protected functions are virtual. private and package functions are not. As such, they cannot be overridden, and it makes no sense to allow them to be abstract. For better or worse, D went the simplified route of tying whether a function is virtual or not to its access level. For the most part, this makes sense, but there are cases where you lose flexibility as a result. - Jonathan M Davis
Jan 30 2019
Okay thanks, I got a solution to my problem. It is a pain that virtual in D is attached to visibility. It makes sense as a default, but, as it is, it reduces what I am able to do. It may cover most cases but not really the others. Thanks, Jonathan
Jan 31 2019