New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: fix inconsistent syntax with function literal declarations #27451
Comments
I'm not sure how this would work syntactically. Right now, the expression But if we do what you suggest, |
There's no 'repeating the type specification', because |
The short form for custom typed literals is not just one type of list, there is the array, which has a comma after each element, there is map with key:pair. Yes, the syntax requires comma for more than one item but statements terminate at the end of line or open of a bracket, they use semicolons, implicit in the newlines. My point is that when I specify a type name for a specific map signature, I don't have to type the signature every time I declare a new map of this given type. A map signature is also in two parts like a function signature, and already the parser can differentiate between a simple alias Making a variable name for a function is not the same as a type alias for any other type, it is an inconsistent rule. If it made it simpler to parse, maybe the function brackets could still be required but at least you can use a shorter thing than the whole damned type signature every time you want to make a closure. I mean, consider the definition of what a closure is - implicitly it does not really have to declare a return value because it shares namespace. This is a limitation with using closures, but also the benefit. But a closure can return a value as well, but to use it this way you have to type the type spec every damn time. It hobbles the closure. First class functions is great but such an unweildy selector requirement makes closures painful to use unless you only want a |
I suggest you propose a different syntax than FuncType{...} |
If I understand correctly, you are suggesting that this should be valid: type fn func(x int) (r int)
var x, r string
var vfn = fn{ if x != 0 { r = 2 }; return } I think the confusion about what |
In that example it would refer to the outermost scope boundary, the package in that case. It is possible to write go programs that use package scope like 'globals' for some types of central node for a storage graph also. The ambiguity that this adds is when the parser encounters a type symbol that is defined in the root of the file/package (depending on capitalisation) is that where it was before 'map or slice', this would just add a third condition 'function'. Likely most of the time someone would only define a couple that are frequently used. |
Maybe I'm misunderstanding you, but it sounds like you are saying that in my example above |
I would think normal scoping rules apply - the I think that the variable names of the parameters and number should match the prototype, and that the () should be there always after the name. Just to not have to repeat the type spec over, and returns can be anonymous, but must match the prototype, same as regular functions. Oh, also, it totally slipped past me - those variable names in the type definition can be there but they do absolutely nothing and distinguish no ambiguities, in fact you are just making them for yourself by using them for no reason. I can sorta see why one might name interface parameter names, if there was anything unclear about it, since it can act like documentation, but as far as I can tell the names do nothing at all to the logic or the compilation except in a function scope where it declares a named variable (and you can't mix unnamed and named in one call either). |
@l0k1verloren I think your suggestion is an interesting idea, and I'm pretty sure it has come up before (I've mentioned it in discussions myself, in the past). To make sure we're all on the same page, if I understand you correctly, what you're suggesting is that function types can be used more regularly. For example, right now we can write: type T = []int
var _ = []int{1, 2, 3} // slice literal of type []int
var _ = T{1, 2, 3} // slice literal of type []int but this doesn't work symmetrically: type F = func(x int) float64
var _ = func(x int) float64 { return math.Sqrt(float64(x)) } // ok
var _ = F{ return math.Sqrt(float64(x)) } // not ok If it were ok, it could shorten function literals (see example above), but also common function declarations like, perhaps: func f F {
return math.Sqrt(float64(x))
} (As an aside, @cznic, in these examples the types of the functions and the type of There are a couple of problems with this suggestion, both of which have been brought up already by @mvdan and @ianlancetaylor , respectively:
var _ = func F { ... } but it would also be more confusing. Alternatively, one might use a different notation for non-function literal bodies (no curly braces). But that would be not backward compatible. Or maybe one would have to write the var _ = F() { ... } but that can't work because
Both of these problems are real. |
I think we could resolve that by retaining the parameter list, while allowing the types themselves to be elided: type F = func(x int) float64
var _ = F(x) { return math.Sqrt(float64(x)) }
func f F(x) {
return math.Sqrt(float64(x))
} However, that could lead to parsing difficulties. (When we see |
See also #21498. |
[Edited to add func]
|
This is an interesting idea but as discussed above there are problems that currently have no good solutions. Closing this proposal; we can reconsider if good solutions are proposed. |
In go, composite literals all follow a rule: if you define it as a type with a type declaration, you can create a literal like this:
But if I do it with a function variable I have to repeat the type specification and the type definition is effectively a no-op because there is no aliasing for function signatures:
If the function declaration was consistent with other composite literals it would greatly encourage the use of them, as for example a package can declare a
type fn func()
and write closures like this:Or line structured, if you like it better:
This is a change that would be backwards compatible because it is only adding the ability to use types as type signature aliases for
func
types, and would cause no changes to how old code works.The text was updated successfully, but these errors were encountered: