What you appear to be after is a recursive relationship with union types: 
"S is a slice type, each of whose elements are either of type S or some 
type T". 

Exactly this is what I'm trying to emphasize: since I'm opting to use the 
explicit generic type inference, I would expect the type system to "detect" 
the type I've defined as a generic type constraint even though the type 
parameter is not strictly related to the T type constraint. If I'd be using 
baseFlatten[T any](acc []T, slice T) ([]T, error) this won't be an issue, 
but in this case I'd be forced to use float32 instead of any, which I would 
like to avoid. So I'm out of ideas how this situation could be overcome 
without explicitly defining the parameter's type. Maybe posting a proposal? 
On Tuesday, August 9, 2022 at 2:16:05 PM UTC+3 Brian Candler wrote:

> Example of type inference in action:
> https://go.dev/play/p/pL7_8zaFIZN
>
> What you appear to be after is a recursive relationship with union types: 
> "S is a slice type, each of whose elements are either of type S or some 
> type T".  AFAIK Go's type system isn't rich enough for that: hence for 
> heterogenous slices you're stuck with interface types (including "any", 
> which is a shortcut for the empty interface, "interface {}")
>
> On Tuesday, 9 August 2022 at 11:53:11 UTC+1 Brian Candler wrote:
>
>> As far as I can see, the problem isn't anything to do with generics, but 
>> with this line alone:
>> input := []any{[]float32{1.0, 2.0}, 1.1}
>>
>> See:
>> https://go.dev/play/p/gUqmUb-Vs_y
>>
>> You've made a slice with mixed elements.  One happens to be a slice of 
>> float32's, and the other happens to be a float64.  Go has no idea that 
>> you'd prefer the second to be a float32.
>>
>> Generic type inference only happens locally at a function call site; it 
>> doesn't propagate backwards to the rest of your program.  Furthermore:
>>
>> 1. When explicitly invoking Flatten[float32](...) you've bypassed the 
>> type inference, by forcing type T to be float32
>> 2. Type inference isn't possible for this function, because your 
>> function's argument (slice any) does not relate to any of the generic type 
>> parameters (i.e. it doesn't make use of "T")
>>
>> On Tuesday, 9 August 2022 at 11:08:42 UTC+1 esi...@gmail.com wrote:
>>
>>> Let's consider the following situation:
>>>
>>> I have generic function which can accepts function arguments defined as 
>>> any. Now if want to know exactly the type of function arguments I have to 
>>> use the reflect package. The problem is that although on function 
>>> invocation we can explicitly define the type constraints, these are not 
>>> taken into consideration when we are matching the concrete types using the 
>>> reflect type switch.
>>>
>>> So let's say, that I have the following function:
>>>
>>> // Flatten flattens the slice all the way to the deepest nesting level.
>>> func Flatten[T any](slice any) ([]T, error) {
>>>         return baseFlatten([]T{}, slice)
>>> }
>>>
>>> func baseFlatten[T any](acc []T, slice any) ([]T, error) {
>>>         var err error
>>>
>>>         switch v := any(slice).(type) {
>>>         case T:
>>>                 acc = append(acc, v)
>>>         case []T:
>>>                 acc = append(acc, v...)
>>>         case []any:
>>>                 for _, sv := range v {
>>>                         acc, err = baseFlatten(acc, sv)
>>>                         if err != nil {
>>>                                 return nil, errors.New("flattening 
>>> error")
>>>                         }
>>>                 }
>>>         default:
>>>                 return nil, errors.New("flattening error")
>>>         }
>>>
>>>         return acc, nil
>>> }
>>>
>>> I would expect that calling the Flatten method in the following way, the 
>>> types to be inferred correctly and the input values to be recognized as 
>>> float32 and NOT float64. Because otherwise I don't see the reason to use an 
>>> explicit type constraint on function invocation.  
>>>
>>> input := []any{[]float32{1.0, 2.0}, 1.1}
>>> result, err := Flatten[float32](input)
>>>
>>> The generic type switch cases as defined in the proposal (
>>> https://go.googlesource.com/proposal/+/HEAD/design/43651-type-parameters.md#generic-types-as-type-switch-cases)
>>>  
>>> is not intuitive, at least for me.   
>>>
>>> Now the question is how could I infer correctly the parameter type 
>>> without explicitly defining the value 1.1 as float32 like this:
>>>
>>> input := []any{[]float32{1.0, 2.0}, float32(1.1)}
>>> result, err := Flatten[float32](input)
>>>
>>

-- 
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/c052db47-96a3-4e2c-8db4-d29784988599n%40googlegroups.com.

Reply via email to