Point-free programming, or "tacit programming", is a convention that highlights the intent without syntactic noise.
For those unfamiliar, wikipedia: https://en.wikipedia.org/wiki/Tacit_programming I want better function composition. "Write a helper function to route values out to values in, like a normal person." Sure, but who needs Go when you have C, eh? A tacit sugaring merely provides a lexically distinctive means to indicate the intent that function f0 should be called with the return value of f1, and f1 of f2, and so on, with reduced syntax. There are a couple layers here, there's an easy win, a possible next step, and well, madness. A. Go uses a thin-arrow, "<" + "-", as a receive/send operator and to signify directionality of a channel. This same operator could be used like so, "c := a <- b()" to assert the following: 1. Token "a" resolves to a function pointer 2. Token "b" returns none, one, or many values, such that "a(b())" is legal. 3. Token "c" can legally be assigned the value of the desugared expression. This suggestion imposes ambiguity between the meaning of "(chan int)(x)<-y(z)" and "(func(int)int)(x)<-y(z)", and I have chaotic intuitions about the meaning of "(func(int)int)(x) <- (chan int)(y)", or even "(func(int)int)(x) <- (chan int)(y) <- z", but x(<-y) is clearly (func[T](T)T)(x)(<-(chan[T] T)(y)). A minimally disruptive solution, then, is to assert that the tip of such a tacit chain must be a full-syntax invokation, e.g. for "f0 <-...f<N-1> <- ?", only "f<N>(...)" is valid. This means expressions like "c0 <- f0 <- f1(f2 <-f3(<-c1))" are unambiguous without a mountain of ellipses. B. At cost of introducing a new concept for Go entirely, it would be convenient to declare a function as "f0 := f1 <- f2 <- f3", resolving as suggested by the statement: "reflect.TypeOf(f0) == reflect.FuncOf([]reflect.Type{reflect.TypeOf(f3).In(0), ..<etc>}, []reflect.Type{reflect.TypeOf(f1).Out(0), ...<etc>})". The straightforward path to implementation would resolve that naively, as suggested by the following: "f0 := func[T handWaving.inT, U handWaving.outT](a... T) (...U) {return f1(f2(f3(a...)))}". A statement like "go f0 <- f1 <-f2 <- f3", assuming "go func[T handWaving.inT](a...T) {f0(f3(a...));}" is legal, would be an attractive pattern. C. Naively, point B suggests that the functions thus concatenated could be assembled as to preallocate the stack for the entire concatenation, omitting the allocations and moves/copies between function calls, and rather writing the return values to the stack for the predecessor function, by analogy, like a reverse closure or a heterogenous recursion. For the example "f0 := f1 <- f2 <- f3", because I expect that statement to only be legal if "f1(f2(f3(..args..)))" is legal, the out-signature of f3 is assignment-compatible with the in-signature of f2, and f2 to f1. Concerns such as an element in the concatenation being recursive, blocking, or corrupting only apply to the function at stack-head; pre-allocating even a potentially large stack exposes only risk shared with allocating the same stack progressively, but with lower instructional segmentation. A possible but unlikely edge-case, if for some reason, a generic function cannot be appropriately stenciled, the optimization being suggested might only partially be applied, or else not applied at all. Ellipses are basically universal for "I give you control, but I expect it back". Loops don't give up control, rather push it on a swing like a child. Go-func commissions an agent, expecting no control. Point A would change the expression somewhat, but by requiring the head of a concatenation to be an execution, the language of "I give, but I expect" is kept, but uses the existing language of sending on channels, "B to A, your turn A", and is suggested as unambiguously extending the "I give, I expect" agreement backwards towards the tail. The symbols suggested are certainly not sacred, either. Point B and C are harder to recommend unequivocally, but could be potently powerful tools for communicating very long but uncomplicated calls. Point B has very few downsides, but represents introduction of a case where a human might understand an expression differently than a parser, while Point C introduces a layer of complexity to serve a use case that, for better or worse, could serve to push a new idiom onto the Gopher community. These three points present no risk to the Go 1 compatibility promise, but I will admit before anyone else that I haven't proven that Point C is worth the investment, and I expect some difficult questions about Point B. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ab4e2604-99aa-4164-a2bf-a9da29d9e0d2n%40googlegroups.com.