Open Dodzey opened 1 month ago
This is known. There is a question on how far to test vs issue an error. I'll have a look at these and check if we should extend what is allowed to be wrong.
Okay. Good to know it is known. I've had another look and as you have previously suggested to me, but I misunderstood, it looks like:
$echo $defined(Foo.missing); // false
$echo $defined(Foo.fun); // true
should work for now. I will test it in my specific scenario.
However it would be really great to be able to check a specific signature to check the validity of @dynamic functions where an interface is not used.
Thanks for the info!
How do you mean that you want to check the dynamic functions?
I have tried a few different things, but I was hoping that something along the lines of:
// Some struct that implements an interface I can check for explicitly...
// This is ok...
interface IBar
{
fn void bar(int, double);
fn void baz(int*);
}
struct Foo (IBar)
{
int i;
double d;
}
fn void Foo.bar(&self, int i_, double d_) @dynamic
{
self.i = i_;
self.d = d_;
}
fn void Foo.baz(&self, int* ip_) @dynamic
{
self.i = ip_ != null ? *ip_ : self.i;
}
// Another struct that has bar with the correct signature, but doesn't have baz at all.
struct FooNoInterface
{
int i;
double d;
}
// Bar - but doesn't match expected signature
// I can check this case ok
fn void FooNoInterface.bar(&self, int i_)
{
self.i = i_;
}
No FooNoInterface.baz - I can't check this without getting a compiler error. I tried....
$echo $defined(FooNoInterface.baz) && $defined(FooNoInterface.baz(int*{}));
$echo $defined(FooNoInterface.baz) ? $defined(FooNoInterface.baz(int*{})) : false;
Neither of which work (allowed to short circuit without compiler error)
92: $echo $defined(FooNoInterface.baz) ? $defined(FooNoInterface.baz(int*{})) : false;
^^^^^^^^^^^^^^^^^^
(<source>:92:47) Error: No method or inner struct/union 'FooNoInterface.baz' found.
I hope that explanation makes sense? Many thanks for the help!
Ahhh.... nested $if appears to work without compilation error:
$if $defined(FooNoInterface.baz):
$if $defined(FooNoInterface{}.baz(int*{})):
$endif
$endif
I might be able to work with that - I'll try to stick it in a macro and do it for $Type and #signature
The $and and $or compile time functions are explicitly for this, since &&
will evaluate both sides.
$echo $and($defined(FooNoInterface.baz), $defined(FooNoInterface.baz(int*{})))
BTW you might want to rethink this though, if you're already doing it at compile time, there is no need for having an interface. Maybe you're not quite clear on how they work, or maybe you're looking for a simpler feature.
For types implementing an interface ad hoc, the expectation is that such an interface is tested at runtime.
Okay, I think (based on what I've picked up of C3 so far) what I want to do is best served at compile time - not sure I have a need for the runtime reflection yet.
I have managed to get something that works, I just need to rework it for the specific use case...
// Match signature without checking return type
macro bool @hasfunctionsig(#s, #fs)
{
return $and(
$defined(#s),
$defined(#fs)
);
}
$assert( @hasfunctionsig(FooNoInterface.bar, FooNoInterface{}.bar(int{})) == true );
$assert( @hasfunctionsig(FooNoInterface.bar, FooNoInterface{}.bar(double{})) == false );
The first place I need to use this in a macro where I'm checking that the function exists and takes no arguments. I have a macro like this:
// @type_has_function_taking_no_args( Foo, bar )
@type_has_function_taking_no_args($Type, #func_name)
{
return @hasfunctionsig( ......, ..... ) // Not sure what I should be using here...
}
But I'm not sure the best way to transform $Type and #func_name to what I need to call @hasfunctionsig(#s, #fs)
This should work in most cases:
macro bool @type_has_function_taking_no_args($Type, #func_name)
{
return @hasfunctionsig($Type.$eval(#func_name), $Type{}.$eval(#func_name)());
}
Consider the following example:
This appears to $echo false for the missing function examples, but also issues an error for all three. I would expect to be able to cleanly get the compile time result of false so I could do conditional stuff in a macro around the existing of the method or not. Is that not how this functionality is supposed to work?