Closed Konstantin8105 closed 3 years ago
I just want to check: have you seen proposal #43651?
Dear @ianlancetaylor,
Yes, I seen that proposal and others.
I hope that issue help to avoid strange too long type clarification like func New[Node NodeConstraint[Edge], Edge EdgeConstraint[Node]] (nodes []Node) *Graph[Node, Edge]
.
Also, for information, present implemented design go2go
cannot create generic in function.
code
Error: prog.go2:34:13: function type cannot have type parameters
How does this fix the verbose function declaration syntax? Could you provide an example of how a graph implementation would look under your proposal?
I don't understand how code like this
func init() {
tools.Numeric = append(tools.Numeric, int, float32)
}
could work in Go. If the init
function has a conditional when setting tools.Numeric
that seems to require a fully dynamic language. Go is statically compiled: all types must be known at compile time.
Dear @deanveloper ,
I remove comments
package graph
var Edge, Node []type
type NodeConstraint interface {
Edges() []Edge
}
type EdgeConstraint interface {
Nodes() (from, to Node)
}
// Graph is a graph composed of nodes and edges.
type Graph struct {
nodes []NodeConstraint
edges []EdgeConstraint
}
func New (nodes []Node) *Graph {
...
}
func (g *Graph) ShortestPath(from, to Node) []Edge { ... }
using:
package main
func init(){
graph.Edge = append(graph.Edge, edgetype)
graph.Node = append(graph.Node, nodetype)
}
type edgetype struct{...}
func (e *edgetype) Nodes() (from, to nodetype) { ... }
type nodetype struct{...}
func (e *nodetype) Edges() (es []edgetype) { ... }
func main() {
var nodes []nodetype
gr := graph.New[Node: nodetype , Edge: edgetype ](nodes)
es := gr.ShortestPath(from,to)
// ...
}
Dear @ianlancetaylor , Yes, I see all types must be known at compile time in other issue comments and document.
Solution
For finding all acceptable types of types slice on go.ast
level and avoid using functions func init(){ ... }, we can create a specific package from standard library with needed operations appending, remove, copy types slices and recording all types using only ast tree.
Using functions from package "go/generic/types" only in global scope. Using in any functions, methods is not acceptable.
import "go/generic/types"
// new types slice
var T = types.Append(types.Init(), float64, int)
// new types slice based on T with adding types and remove type `int`
var E = types.Append(T,
float32,
complex64,
).Remove(int)
// work like : type S = T
var S = types.Rename(T, T) // &S == &T
// new local types slice equal external types slice and add types
var myNumeric = types.Rename(Append(tools.Numeric, float32, float64), tools.Numeric)
In that case - need add in struct go.ast.File:
type File struct {
... // exist values
// Types is map of types slices names and acceptable types name for each
// Example:
// Types = [][]string{
// "T": []string{ "float64", "int"},
// "E": []string{ "float64", "float32", "complex64"},
// "S": []string{ "T"},
// "tools.Numeric" : []string{ "float32", "float64"},
// "myNumeric": []string{ "tools.Numeric"},
// }
Types map[string]string
}
Present Go package parser
parse that types operations without ast.BadDecl
or ast.BadExpr
.
See code.
package main
import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/token"
"strings"
)
func main() {
fset := token.NewFileSet() // positions are relative to fset
src := `package main
import types "go/generic/types"
var (
A = types.Init()
B = types.Append(A)
C = types.Init()
D = types.Append(Init())
E = types.Append(D, int)
F = types.Append(types.Init(), int8, int16)
H = types.Rename(types.Append(C, floats), C)
G = types.Remove(types.Rename(types.Append(Init(), string, int8, int16), A), int8)
)
var T = types.Append(types.Init(), float64, int)
var E = types.Append(T,
float32,
complex64,
).Remove(int)
var S = types.Rename(T, T)
`
// Parse src but stop after processing the imports.
f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
if err != nil {
fmt.Println(err)
return
}
var buf bytes.Buffer
err = ast.Fprint(&buf, fset, f, nil)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("AST tree have ast.BadDecl or ast.BadExpr :", strings.Contains(buf.String(), "Bad"))
fmt.Println(buf.String())
}
result:
AST tree have ast.BadDecl or ast.BadExpr : false
0 *ast.File {
1 . Doc: nil
2 . Package: 1:1
3 . Name: *ast.Ident {
4 . . NamePos: 1:9
5 . . Name: "main"
...
If we can't use init
functions, I don't understand the purpose of types.Append
or the Remove
method. The person writing the code should be able to write down all possible types. Why use a syntax like types.Append
rather than just writing a list?
At the first part of question.
About types manipulations Append
, Remove
and ...
In according to Type Parameters - Draft Design.
I can write:
package mymath
type Numeric interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64,
float32, float64
}
// Mult is naive matrix multiplication
func Mult[T Numeric] (A,B,C [][]T) {
n := len(A)
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
for k := 0; k < n; k++ {
C[i][j] += A[i][k] * B[k][j]
}
}
}
}
package main
import "fmt"
func main() {
A64 := [][]float64{{2}}
mymath.Mult(A64,A64,A64)
fmt.Println(A64)
}
Now, that code is valid. code
But I do not understood - How I can add type complex64
in mymath.Numeric
from package main
?
Because this acceptable from math point of view and go2go point of view.
At the second part of question
About types list any
.
We can add a function like:
import types "go/generic/types"
var T = types.Any() // Any types
But I do not understood - How I can add type complex64 in mymath.Numeric from package main?
You can't. Go is not a dynamic language. All types need to be known at compile time. You can't change types at run time.
About types list any.
We could add a function types.Any
but what would we gain?
Dear @ianlancetaylor ,
But I do not understood - How I can add type complex64 in mymath.Numeric from package main?
You can't. Go is not a dynamic language. All types need to be known at compile time. You can't change types at run time.
In go2go
design type Numeric interface{ ... }
in package mymath
analyzed at compile time.
That type uppercase so exported and we can use them in external packages (for example package main
).
But we cannot append new type in type mymath.Numeric
from external packages at compile time. (it is like algorithms singly linked list
or tree without knows parents
).
In my point of view, that option help if somebody forgot add needed types.
My main goal of that issue - trying to avoid long type clarification like func New[Node NodeConstraint[Edge], Edge EdgeConstraint[Node]] (nodes []Node) *Graph[Node, Edge]
is impossible.
Feel free for close that issue. Thank you.
Yes, the generics proposal has limitations. Those are because we want Go to remain a statically compiled language. It's true that there are advantages to languages with a more dynamic type system, but Go is not one of those languages.
Create that proposal in according to https://github.com/golang/proposal#the-proposal-process .
Type of type
In according to questions from template:
func New[Node NodeConstraint[Edge], Edge EdgeConstraint[Node]] (nodes []Node) *Graph[Node, Edge]
code.must not generate code at runtime - Go needs to work in environments (e.g. GCP) where run-time code generation is not allowed
Minimal example
For present language design:
Types slice manipulation
Types slice:
any
Acceptable types slice initialization
Not acceptable slice of types
Useful operations
Create a copy of types slice
Append new type
Append types slice to types slice
Append new type to external package
Remove type from external package
Scope
Type slice is cannot by changed in any functions, methods, except function
func init() {...}
. So, we can create a tests for avoid some types in types slice.Generic prototype with one types slice
Examlpe 1
External package
tools
with empty types sliceUse package
tools
:Example 2
Example based on code from https://blog.golang.org/why-generics.
Using:
Example 3
Example based on code from https://github.com/golang/proposal/blob/master/design/15292/2013-12-type-params.md#syntax
Generic prototype with few types slice
Example 1
External package
tools
with empty types sliceExample 2
Swap types
Example 3
Example based on code from https://github.com/golang/proposal/blob/master/design/15292/2013-12-type-params.md#syntax
Example 4
Example with 3 types slices in one struct. In struct structure used 2 types slices and 1 in struct method.
Useful generics
Using in go package
math
Code based on function math.Pow
Types for-range
I do not know - is it useful?
or may be for tests
Pointers in types slice
Embedded
Generic from exist code
Replace on external package level
We have package with math operations sparse and we want to use that package but with changing type from
float64
tofloat32
.As we see - it is easy for adding new types, for example in future
float128
and other.Replace on function level for external package
For example, we found function:
But we want use with another types in our code:
TODO
I do not think about:
Feel free for close