meh / nucular

A reactor in D.
12 stars 4 forks source link

Look into .tupleof to pass constructor arguments to Connection objects. #9

Open meh opened 11 years ago

meh commented 11 years ago
10:50:09 < another question, but I don't know if this is possible at all
10:50:30 < with startServer
10:51:06 < I'd like to make it a variadic or similar method
10:51:09 < as in
10:51:23 < I have a subclass of Connection
10:51:38 < that has an initialize method that has its signature
10:51:51 < and I want to call it with the rest of the arguments passed to startServer
10:51:57 < is it possible at all?
10:52:04 > ya of course
10:52:10 < how?
10:52:18 > nothing's impossible in D :D
10:52:21 > so let me get it clear
10:52:26 > I am looking at startServer
10:53:45 > they all take a type parameter T which is implicitly convertible to Connection - so you want to receive arguments to Connection.initialize at the end of startServer?
10:54:02 > there's a gazillion overloads of startServer here :<
10:54:22 < I know, don't kill me :(
10:55:19 < I want to call Connection.initialize with the rest of the arguments when it's being initialized
10:55:30 < for instance, when using connect it's initialized inside connect
10:55:40 < but with startServer it's initialized when a new connection comes
10:55:56 < so I'd have to store the passed arguments to startServer in the server instance
10:58:56 > well you can use a variadic template: void foo(InitArgs...)(InitArgs initArgs), then make a tuple of it: Tuple!(InitArgs) storedArgs = tuple(initArgs); // can use type inference here, but typed out in full for clarity
10:59:41 > but of course the size of the tuple depends on the amount of arguments, so you need some way to store it, which you can do with std.variant for example
11:00:58 > if you don't mind returning a templated type from startServer, like Server!(InitArgs), then you can of course just do that
11:01:10 < nah, I'll use std.variant
11:01:59 > note that the template instance "Variant" is not big enough in most cases, it depends on the system but it's often just something like 12 bytes
11:02:18 < oh
11:02:22 > so you'll want to store a VariantN instance with a custom maxDataSize argument
11:03:29 > "VariantN is a discriminated union type parameterized with the largest size of the types stored (maxDataSize) and with the list of allowed types (AllowedTypes). If the list is empty, then any type up of size up to maxDataSize (rounded up for alignment) can be stored in a VariantN object."
11:04:13 > you can then put a static assert in the startServer method taking the variadic arguments for initialize making it error if there's not enough room for the arguments
11:04:53 > (the user can always just pass a class reference or a pointer to heap memory or something instead when there's not enough space directly in the VariantN)
11:06:11 > something like: static assert(Tuple!(InitArgs).sizeof <= maxDataSize, "arguments for initialize are too big");
11:06:52 < one question
11:07:08 < the foo
11:07:14 < would be startServer, right?
11:07:30 > yeah
11:07:35 < as in, startServer(blalaparameters, InitArgs...)?
11:07:38 > but you have so many of them...
11:07:42 < yeah I know
11:07:49 < it's a pain in the ass
11:07:59 > startServer(InitArgs...)(blahblahstuff, InitArgs initArgs)
11:08:07 < oh
11:08:17 < what about T : Connection?
11:08:26 < before InitArgs... ?
11:08:29 > that way, InitArgs is a Type Tuple and initArgs is an expression tuple containing all arguments passed after the regular parameters
11:08:30 > yeah
11:08:33 > that works fine still
11:08:45 > startServer(T : Connection, InitArgs....)(etc)
11:08:49 < this black magic is giving me a boner
11:09:08 > D's metaprogramming facilities own
11:09:22 < yeah, I'm seriously impressed
11:11:14 < how do I then call the method with the tuple?
11:14:03 > bleh yeah you need the types later. Just scrap the variant and generate some code. Like make a nested function in startServer like: void callInit() { (cast(T)_connection).initialize(initArgs); } and store a delegate to it or something