Creating struct and adding interface does not raise an error if interface is not implemented
This struct does not implement Printable, but not error is raised
module test;
import std::io;
struct Example (Printable)
{
ushort row;
ushort offset;
ushort col;
}
fn void main()
{
Example ex;
io::printn(ex);
}
That's because both the Printable methods are marked as @optional (https://github.com/c3lang/c3c/blob/master/lib/std/io/formatter.c3#L7-L11) so you can choose which one to implement. It does come with the side effect of not requiring either to be implemented though.
Ah I see, feel free to close this if that's intensional behaviour. Perhaps verifying at least one thing in the interface is implemented would be a nice solution?
That is not necessarily correct though, is it?
Unless there was some additional constraint for interfaces that have a way to explain that one or both methods need to be implemented. I think this is rare.
That is not necessarily correct though, is it?
Intuitively you would need at least one thing to implement an interface, but the problems come when you need 2 out of 4 options that's tricky
Should I close this?
One suggestion might be some sort of contract on the interface where such things could be specified
for one option or another
<*
@optional_sets {{to_constant_string}, {to_format}}
*>
interface Printable
{
fn String to_constant_string() @optional;
fn usz? to_format(Formatter* formatter) @optional;
}
Either example1 and example2 or example2 and example3
<*
@optional_sets {{example1, example2}, {example2, example3}}
*>
interface Example
{
fn String example1() @optional;
fn String example2() @optional;
fn String example3() @optional;
}
you could also theoretically reuse @require, but without a context-sensitive keyword to refer to the type implementing the interface it could be a bit of a hack:
<*
@require $defined({}.to_constant_string) ||| $defined({}.to_format) : "You must implement either to_constant_string or to_format"
*>
interface Printable
{
fn String to_constant_string() @optional;
fn usz? to_format(Formatter* formatter) @optional;
}
or
<*
@require $defined(implementer.to_constant_string) ||| $defined(implementer.to_format) : "You must implement either to_constant_string or to_format"
*>
interface Printable
{
fn String to_constant_string() @optional;
fn usz? to_format(Formatter* formatter) @optional;
}
probably not as good as @joshring's idea, but just throwing an idea out there.