digitalmars.D.learn - Static opCall Factory Method Doesn't Work for Inner Classes
- eris (45/45) Jan 12 2010 Hello fellow D'ers...
- Simen kjaeraas (14/19) Jan 12 2010 Does the inbox need a pointer to the kernel class? If so, you're ferked.
- eris (32/56) Jan 12 2010 Thanks, Simen. I'll take a look at my code. This whole effort is the r...
Hello fellow D'ers... I'm writing a message passing kernel and scheduler. "User-space" programs communicate with each other and the kernel through inboxes and outboxes which are allocated and tracked by the kernel. If a user-space program wants to allocate an inbox called "stdin" and an outbox called "stdout" currently they simply ask the kernel to create one for them. For example: auto my_stdin = kernel.createInbox(String)("stdin"); auto my_stdout = kernel.createOutbox(String)("stdout"); This works fine for me. It is a pain, however, to make a new "create" method everytime I want to define a new structure. I'd much rather use the "static <classname> opCall" mechanism which allows you to simply call the classname to have it generate an instance of that class. Now the static opCall pattern I've gotten to work: class A { ... static A opCall(args) { return new A(args); } } auto a = A(args); That works fine if you want instances of a factory created by calling the factory. For example: CarFactory car = CarFactory(args); It's a little syntactically awkward, but it works. My problem is I want the kernel to act as a factory for inboxes, outboxes and a bunch of other things. I'd like this to work: class Kernel { ... class Inbox { ... static Inbox opCall(char[] name) { return new Inbox(name); } } class Outbox { ... static Outbox opCall(char[] name) { return new Outbox(name); } } ... } That way I just create a static opCall method for each kernel object and I get a factory method which could be used like this... auto my_inbox = kernel.Inbox("stdin"); auto my_outbox = kernel.Outbox("stdout"); BUT.... Every syntax combination in D to express a static opcall on an inner class doesn't work. Both 'ldc' and 'gdc' generate compiler errors that say that 'this' is not available for static opCalls. When I take the 'static' keyword off the opCall declaration the compiler error becomes something like: 'this' is required to access the opCall method. I was getting pretty tired when I gave up on this last night, but the problem is still eluding me. Am I just trying to do this the wrong way? I know the "createInbox" method works. Perhaps I should make separate factories for every structure, but that seems harder than just making create methods. If I can get this to work, I think I could create a mixin that would generate automatic factory methods. (This is probably obvious and I was just too tired last night.) Thanks for your help, eris
Jan 12 2010
eris <jvburnes gmail.com> wrote:Every syntax combination in D to express a static opcall on an inner class doesn't work. Both 'ldc' and 'gdc' generate compiler errors that say that 'this' is not available for static opCalls. When I take the 'static' keyword off the opCall declaration the compiler error becomes something like: 'this' is required to access the opCall method.Does the inbox need a pointer to the kernel class? If so, you're ferked. Well, not really, but then you have to explicitly pass it to opCall. See, to get this to work, you do this: class foo { static class bar { // static inner classes have no 'outer' pointer static bar opCall( ) { return new bar( ); } } } Hope this helps. -- Simen
Jan 12 2010
Simen kjaeraas Wrote:eris <jvburnes gmail.com> wrote:Thanks, Simen. I'll take a look at my code. This whole effort is the result of a "single responsibility" refactoring where the kernel has responsibility for inbox and outbox creation since they implement kernel functionality. The user space programs really only have an interface into these objects, such as... interface Inbox(T) { T read(); bool isEmpty(); .. } interface Outbox(T) { void send(T msg); .. } class Kernel { ... // kernel inbox functionality including blocking read on empty class MsgBox(T) : Inbox!(T) { static MsgBox(T) opCall(T)(char[] name) { return new MsgBox!(T)(name); } T read() { if (isEmpty()) Fiber.yield; else return ... } ... } auto my_inbox = kernel.MsgBox!(String)("stdin"); Or at least that is what I was trying to achieve -- an interface into the kernel, literally. This way the kernel maps the internal MsgBox object to an interface for the userland program to use. Userland just sees my_inbox.read and not the implementation and doesn't care about kernel blocking. I'm going to do another round of my refactoring and see if the problem doesn't resolve itself. Perhaps the kernel should use external classes for the factories that aren't normally available to user-space programs. Or maybe I'm making it too hard. If userland wants it's own inbox, fine, but the kernel won't recognize it unless it has been registered with it. I think part of the issue is that message sending and receiving between mailbox methods contain blocking functions if an outbox is full or an inbox is empty. Those blocking functions are actually implemented by kernel primitives. That's why userland needs an interface into them, but the actual mailbox methods need to be running in the kernel. If that makes *any* sense. :-) (the problem may be that the program I'm working on so relatively large and I accidentally started working on one of the intermediate refactors) erisEvery syntax combination in D to express a static opcall on an inner class doesn't work. Both 'ldc' and 'gdc' generate compiler errors that say that 'this' is not available for static opCalls. When I take the 'static' keyword off the opCall declaration the compiler error becomes something like: 'this' is required to access the opCall method.Does the inbox need a pointer to the kernel class? If so, you're ferked. Well, not really, but then you have to explicitly pass it to opCall. See, to get this to work, you do this: class foo { static class bar { // static inner classes have no 'outer' pointer static bar opCall( ) { return new bar( ); } } } Hope this helps. -- Simen
Jan 12 2010