Hacker News new | past | comments | ask | show | jobs | submit login

Okay, macros. Either way, it provides what most people are asking for in generics (not you, perhaps), even if the implementation isn't exactly pleasant. From a practical standpoint, there really isn't a whole lot of difference in utilizing max (other than the ugliness):

    # Common pattern in other languages
    max<int>(1, 2)

    # Similar pattern in Go
    #go:generate gofmt -r 'T -> int' -w max.go
    max(1, 2)
But yes, "true" generics are much more complicated (and arguably impossible in Go without major changes to the language), I realize. A number of languages that even claim to have generics fall short on that front, which is a path the Go authors have said they do not want to go down.

Although you do have me curious how you'd implement max in C in this type-safe way using standard tooling:

    #define max(a, b) (a > b ? a : b)
...obviously wouldn't fit the bill since it doesn't enforce types like to Go version does.



> Either way, it provides what most people are asking for in generics (not you, perhaps), even if the implementation isn't exactly pleasant.

No, it doesn't. Not even close.

Even something like generic List<T> and sort<T>(List<T>) (separately compiled) will fall down because that simplistic scheme doesn't give each generic type and function a different name, and there's no way for sort<T> to look up whatever name List<T> got instantiated into.

There are also all sorts of hairy issues you will get into when you have name resolution and separate compilation: how do you make sure the macro got instantiated into the same lexical environment that it got declared in? This matters a lot when you have package A exporting a bunch of generic types and functions for package B to use, and it's going to be B doing the expansion using B's types. Even if you set up things just right to resolve the names in the proper lexical scope, how can B's expansion of A's templates use private symbols from A?

Finally, you have the dreaded C++ template error message problems, except they're going to be even worse with this scheme because the compiler is going to complain about code post-textual-replacement, with no way to interpret the chain of events that led to the error. At least clang and GCC have lots of semantic information that they can use, since templates are expanded during semantic analysis.


   #define defmax(name, type) type name(type a, type b) { return a > b ? a : b; }
This seems to be exactly how you would define a "generic" max function in Go with the current tooling, too. Which is a shame because C macros just aren't good enough.


Good example. Thanks.

> Which is a shame because C macros just aren't good enough.

No disagreement here. However, that still perfectly satisfies what may people claim they want in generics, especially those who most frequently trumpet that Go is lacking them. If we took that exact macro and added a little hypothetical syntactical sugar:

    template<type> type max(type a, type b) {
        return a > b ? a : b;
    }

    max<int>(1, 2);
a lot of people (not everyone) would be very happy, even though there is no theoretical difference at all. I've seen countless proposals for Go generics that do nothing more than that, but have been rejected for obvious reasons. That's where I'm coming from.


There's a huge theoretical difference. To name one obvious example, the template is hygienic with respect to name collisions, while the macro isn't.


I think you may be reading too much into the hypothetical implementation. It was highlighted as nothing more than syntax sugar, after all. If all you do is translate:

    template<type> max(...) into #define defmax(type) ...
and

    max<int>(...) into defmax(int); max(...)
  
The resultant code will be identical once it has gone through the preprocessor. All you are gaining is prettier looking code, which shouldn't be discounted, but generics are about more than that. Yet this example would be quite satisfactory to many regardless; curiously even you seemed excited about it.


> The resultant code will be identical once it has gone through the preprocessor.

Well, sure. Hand-written assembly is also identical to compiled code, but we still have compilers :)

> All you are gaining is prettier looking code, which shouldn't be discounted, but generics are about more than that.

Yes.

> Yet this example would be quite satisfactory to many regardless; curiously even you seemed excited about it.

I don't think macros are a satisfactory replacement for generics, no. I don't know how I seemed "excited" about it.


> Well, sure. Hand-written assembly is also identical to compiled code

I mean when you convert the template<type> statement to the #define statement with the hypothetical preprocessor, it would be the same as if you had written the same code using #defines originally. They are functionally interchangable. If this satisfies generics in your mind (I don't think this describes you, for what it is worth), then standard C macros are more than sufficient to cover all the cases you would want, albeit less pleasant to type.

> I don't think macros are a satisfactory replacement for generics, no. I don't know how I seemed "excited" about it.

Consider your previous post misinterpreted then. It read to me like you thought the hypothetical code was theoretically different and solved problems with the previously provided macro, even though it was the exact same macro in both cases. The only difference was the slightly different syntax. Which, I might add, anyone can fairly easily add something similar to their Go code if they really wanted to.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: