Hacker News new | ask | show | jobs
by sltkr 698 days ago
This doesn't function as an interface though. You cannot pass a FooBar to a function that expects a Foo, for example, and although you can fairly easily reference the Foo-part of a FooBar instance (`foobar.Foo`) there is no way to pass e.g. an array of FooBar instances to a function that takes a slice of Foo[] as its argument. That's the problem to be solved.
2 comments

Ok, Go generics is pretty limited but you can achieve this in C++ via concepts.

    #include <iostream>
    #include <string>
    #include <type_traits>

    // Concept to check for 'foo' field of type int
    template <typename T>
    concept HasFooInt = requires(T t) {
        { t.foo } -> std::convertible_to<int>;
    };

    // Concept to check for 'bar' field of type string
    template <typename T>
    concept HasBarString = requires(T t) {
        { t.bar } -> std::convertible_to<std::string>;
    };

    // Generic function that accepts T with either 'foo' or 'bar'
    template <typename T>
    requires HasFooInt<T> || HasBarString<T>
    void printField(const T& t) {
        if constexpr (HasFooInt<T>) {
            std::cout << "foo: " << t.foo << std::endl;
        } else if constexpr (HasBarString<T>) {
            std::cout << "bar: " << t.bar << std::endl;
        }
    }

    struct Foo {
        int foo;
    };

    struct Bar {
        std::string bar;
    };

    struct FooBar {
        int foo;
        std::string bar;
    };

    int main() {
        Foo s1 { 42 };
        Bar s2 { "hello" };
        FooBar s3 { 100, "world" };

        printField(s1); // prints: foo: 42
        printField(s2); // prints: bar: hello
        printField(s3); // prints: foo: 100 (prefers foo due to order of checks)
        
        return 0;
    }
Totally achievable by using interfaces instead of structs

    type Foo interface {
      Foo() int
    }

    type Bar interface {
      Bar() string
    }

    type FooBar interface {
      Foo
      Bar
    }
Then functions that accept a Foo will also happily take a FooBar. Does not solve the problem of passing a FooBar[] to a function that expects Foo[] but that can be solved with generics or a simple function to convert FooBar[] to Foo[].