golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.24k stars 17.47k forks source link

proposal: reflect: add generic type arg info to reflect.Type #54393

Open aaronc opened 2 years ago

aaronc commented 2 years ago

I'm not sure if this has been discussed already (I couldn't find a prior issue), but currently reflect.Type has no direct methods to retrieve the type arguments of generic types.

The only way to retrieve these type arguments is by parsing the string returned by Type.Name() which includes fully qualified package names and could look something like this in a complex case: MyGenericType[some/package.Foo, map[string]other/package.Bar]. This string is not easy to parse because of the possibility of nested type arguments, maps, slices, etc.

I propose adding methods to reflect.Type to retrieve these type arguments programmatically:

NumTypeArg() int
TypeArg(i int) Type
ianlancetaylor commented 2 years ago

I'm not sure TypeParam is the right name here. The type parameters are the parameters that appear in the type definition. I think that what you are describing is what we usually call the type arguments.

robpike commented 2 years ago

@ianlancetaylor Those terms are not the ones I know from my youth. We used to talk about formals and actuals, which carry a distinct meaning already. Modern computing's use of the terms parameters and arguments results in a domain-specific redefinition of true synonyms in normal English. However, I admit that redefinition is not unique to Go.

I wonder why this terminology shift happened.

icholy commented 2 years ago

Adding methods to reflect.Type would be a breaking change.

zephyrtronium commented 2 years ago

@icholy reflect.Type has unexported methods, so every type which implements it is in package reflect and can be updated along with the interface. Is there another sense in which it would be a breaking change to add methods to reflect.Type?

ianlancetaylor commented 2 years ago

@robpike That's true, now that you mention that I remember "formal" and "actual" as well. But today even the Go spec speaks of "function parameters" and "function arguments".

apparentlymart commented 1 year ago

FWIW I also learned "formal parameters" in school but have tended to use "parameter" and "argument" in my writing for at least the last decade or so because that seems (anecdotally) to be the current familiar jargon across various different language specs and tutorials.

It is unfortunate that in plain English "parameter" and "argument" are not clearly differentiated in the way that is intended in this context, but that seems to be a common characteristic of plain words adopted as jargon. The dictionary tells me that "formal" as a noun means "an evening gown" and that "actual" isn't a noun at all, so those words don't seem to be obviously better cognates. I think it's beneficial to go with the flow here and use terms that people are likely to have encountered in other languages and in tutorials. (even though this sort of jargon evolution does make me notice my age.)

With the obvious caveat that Wikipedia is a tertiary source rather than an authority, I do note that Parameter (computer programming) mentions both pairs of terms, but gives priority to "parameter" and "argument" while relegating "formal argument" and "actual argument" to secondary position. With that said, the section Parameters and Arguments does go on to acknowledge the inconsistency of usage and potential confusion between them.


Interestingly, one of the first tutorials I found when looking for examples -- the "Functions" section of A Tour Of Go -- seems at first read to be using these terms without defining them and switching somewhat carelessly from one to the other without explaining their relationship:

A function can take zero or more arguments.

In this example, add takes two parameters of type int.

As a reader who already knows the common meanings of "arguments" vs. "parameters" I probably wouldn't noticed this if I wasn't explicitly looking for examples. Perhaps what we can learn from this example is that the terms "argument" and "parameters" are so familiar to programming language learners that explicit definition and distinguishing remarks felt unnecessary here. (I'm assuming that a non-trivial number of people have successfully learned Go in part by following this tour.)

atdiar commented 1 year ago

Seems about the same difference between variables and values to me. Parameter is to variable what argument is to value.

aaronc commented 1 year ago

Happy to switch this proposal to TypeArgument, TypeArg or even TypeActual. What do people prefer?

Does the proposal otherwise sound reasonable?

icholy commented 1 year ago

It should probably be

NumTypeArg() int
TypeArg(i int) Type
aaronc commented 1 year ago

I've changed this proposal to use TypeArg for now. That seems reasonable. Happy to change to a different naming if people prefers otherwise.

icholy commented 1 year ago

@aaronc NumTypeArgs should be NumTypeArg to match the rest of the relect.Type methods.

aaronc commented 1 year ago

@aaronc NumTypeArgs should be NumTypeArg to match the rest of the relect.Type methods.

Updated

mdempsky commented 1 year ago

Note that if you have a local defined type declared within a type-parameterized function, then that function's type parameters are also implicit type parameters of the defined type.

For example:

func F[X any]() any {
    type T int
    return T(0)
}

then F[X].T is implicitly parameterized by X.