www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Package functions cannot be abstract?!

reply Jonathan Levi <catanscout gmail.com> writes:
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
next sibling parent Neia Neutuladh <neia ikeran.org> writes:
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
prev sibling next sibling parent Marco de Wild <mdwild sogyo.nl> writes:
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
prev sibling next sibling parent reply Benjamin Schaaf <ben.schaaf gmail.com> writes:
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
parent reply Neia Neutuladh <neia ikeran.org> writes:
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:
 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?
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.
Jan 30
parent reply Neia Neutuladh <neia ikeran.org> writes:
On Wed, 30 Jan 2019 17:21:31 +0000, Neia Neutuladh wrote:

 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:
 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?
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.
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.
Jan 30
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
prev sibling next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
 abstract
By 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
prev sibling parent Jonathan Levi <catanscout gmail.com> writes:
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