Re: [go-nuts] fstest.MapFS ReadDir does not set name field for entry.Name()

2022-04-02 Thread Ian Lance Taylor
On Sat, Apr 2, 2022 at 2:46 PM Kalen Krempely  wrote:
>
> 2) As a follow up question I find it weird that VerifyDir needs to take in 
> both a filesystem and the root path. (ie: `VerifyDir(fsys fs.FS, dir 
> string)`) That is, the calling code will be something like 
> VerifyDir(os.DirFS("/some/path"), "/some/path"), where /some/path is passed 
> in twice essentially since there is no way to get the path from fs.FS. Is 
> this common? Or am I miss understanding something?

That is correct: there is no way to get the path from fs.FS.  In
general, an fs.FS can be anything that looks like a file system, such
as a zip file; it need not have a path at all.

Ian

-- 
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/CAOyqgcU9UfJ5RAD7fiDw2MeV6zuGu0n7eDSdPwnhg%2B46WsTjBg%40mail.gmail.com.


Re: [go-nuts] Tacit Golang?

2022-04-02 Thread Bakul Shah
If I understand you right, you seem to want to use "<-" as the "compose" higher 
order function but as an infix operator. That is, instead of "value := 
F(G(args...))", you want to be able to write "value := (F <- G)(args...)". 
Further, "F <- G <- H" means "F <- (G <- H)". F, G &H are functions such that 
F(G(H(args...)) is a valid expression, if args... is valid.

My gut instinct says Go is the wrong language to extend for tacit programming. 
If you look at existing code, my guess is you won't find very many instances of 
code that can be mapped to tacit programming. So low "bang for the buck". 
Second the optimization that you talk about in point C. is likely not very 
important or even meaningful. Typically it is the *called* function that pops 
the stack, not the caller and unless you can inline things like (F<-G<-H) you 
can't collapse three pops into one. Third, in Go you can't short circuit error 
returns. Thus if H can return an error, you can't use it in a pipeline! You 
have to handle the error at the call site of H. Ideally one (or at least *I*) 
would want something like F(G(H(...)) to return to the call site of F with an 
erorr, without executing F or G in case H fails.

> On Apr 1, 2022, at 3:41 PM, Sam Hughes  wrote:
> 
> 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 <- ?", only "f(...)" 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), ..}, 
> []reflect.Type{reflect.TypeOf(f1).Out(0), ...})". 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 chan

Re: [go-nuts] fstest.MapFS ReadDir does not set name field for entry.Name()

2022-04-02 Thread Kalen Krempely
Thanks Ian for the reply!

*1)* I think I figured out what was going on. Basically, I need to pass the 
root path to my verifyDir function and just have the fstest.MapFS contain 
the sub elements, rather than the full paths.

That is, the example test code needs to be:
t.Run("some test", func(t *testing.T) {
   fs := fstest.MapFS{
  "test/path_hi_there": {Mode: fs.ModeDir},
   }

   err := VerifyDir(fs, "/some/long")
   if err != nil {
  fmt.Println("unexpected error %+v", err)
   }
})


*2)* As a follow up question I find it weird that VerifyDir needs to take 
in both a filesystem and the root path. (ie: `VerifyDir(fsys fs.FS, dir 
string)`) That is, the calling code will be something like 
VerifyDir(os.DirFS("/some/path"), "/some/path"), where /some/path is passed 
in twice essentially since there is no way to get the path from fs.FS. Is 
this common? Or am I miss understanding something?

On Wednesday, March 23, 2022 at 2:12:24 PM UTC-7 Ian Lance Taylor wrote:

> On Wed, Mar 23, 2022 at 2:01 PM Kalen Krempely  wrote:
> >
> > I am trying to use fstest.MapFS to help with testing, but I noticed the 
> mapfs implementation of ReadDir does not set the name field which is quite 
> problematic as I rely on that in my code.
> >
> > Example Test Code:
> > t.Run("some test", func(t *testing.T) {
> > fs := fstest.MapFS{
> > "/some/long/test/path_hi_there": {Mode: fs.ModeDir},
> > }
> >
> > err := VerifyDir(fs, "/some/long/test/path_hi_there")
> > if err != nil {
> > fmt.Println("unexpected error %+v", err)
> > }
> > })
> >
> > Snippet of Code:
> > func VerifyDir(fsys fs.FS, dir string) error {
> > entries, err := fs.ReadDir(fsys, ".")
> > if err != nil {
> > return err
> > }
> >
> > for _, entry := range entries {
> > if !entry.IsDir() {
> > continue
> > }
> >
> > fmt.Println("expected entry.Name() to not be empty:", entry.Name())
> > path := filepath.Join(dir, entry.Name())
> > // do stuff with path...
> > }
> >
> > return nil
> > }
> >
> > Any ideas around this? Any practical examples of using fstest.MapFS to 
> learn from?
>
> As far as I can tell testing.MapFS.ReadDir does return values for
> which the Name method returns a non-empty string. Can you show a
> complete, stand-alone, program that demonstrates the problem you are
> describing? Thanks.
>
> Note that in normal use the strings used as names when initialization
> a testing.MapFS should not start with a slash. See
> https://pkg.go.dev/io/fs#ValidPath.
>
> Ian
>

-- 
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/70812b6e-ab4a-43f6-8a75-1c58b594da99n%40googlegroups.com.


Re: [go-nuts] Re: Tacit Golang?

2022-04-02 Thread Sam Hughes
Yep. That’s the status quo. My tongue-in-cheek response to that as
objection is “If simply sufficient utility for a given task were valid as
objection to a new utility, why Go over C?” If you’re not posing that as
objection, no need to dwell on it.

Yeah. That’s exactly the kind of behavior I want to improve on. If you
reimplemented as “[T constraints.Number]”, then you would have a reasonably
efficient means of expressing even very deep pipelines of numerical
transformations, with the caveat that one is not able to change the arity
for any stage boundary. You can’t reduce the constraint on T, lest you be
unable to do mathematical operations without reverting to interface and
type-assertion semantics, losing the benefit of generics over interfaces. Now
you have two sets of almost identical pipeline boilerplate — more if you
intend stochastic gradients or other matrix operations.

Generics also can’t cover the case of multiple values at the boundary of a
stage. You could define types for various combinations of values, function
pointers, and errors, and create the most godawful, disgusting pile of
moldering spaghetti.

The three most effective ways to get around this are to A,
marshal/unmarshal from a byte-slice, B, use variadic parameters of type
empty interface, and C, codegen. All three add unnecessarily heavy mental
overhead, and excepting C, sacrifice safety and performance guarantees.

So in short, yes, that playground snippet is exactly the kind of utility
that works in the same way that a tape-covered racket works as an oar.

On Fri, Apr 1, 2022 at 10:35 PM Henry  wrote:

> Something like this? https://play.golang.com/p/rhu9PX9GSbp
>
> On Saturday, April 2, 2022 at 5:41:52 AM UTC+7 sam.a@gmail.com wrote:
>
>> 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 <- ?", only "f(...)" 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), ..},
>> []reflect.Type{reflect.TypeOf(f1).Out(0), ...})". 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 p

[go-nuts] Alternative generics design with some interesting aspects

2022-04-02 Thread will....@gmail.com
Hey all,

Congrats to the Go Team for shipping generics!

I was experimenting with a design for generics for a long time. I thought 
I'd share it anyway for fun. I think it has some interesting (IMHO) aspects 
and trade-offs compared to the design that shipped:

   - Type variable declarations are implicit
   - Type arguments for functions are implicit
   - Type variable constraints can be omitted for the empty interface
   - Methods can be generic
   - Operations are represented with generics as normal methods
   - It can simplify the Go language specification
   
Here's a quick sample:

type Number interface {
$N Add($N) $N
}

type MyInt struct {
my int
}

func (x MyInt) Add(y MyInt) MyInt {
return MyInt{my: x + y}
}

type MyFloat struct {
my float64
}

func (x MyFloat) Add(y MyFloat) MyFloat {
return MyFloat{my: x + y}
}

func Add[$N Number](a, b $N) $N {
return a.Add(b)
}

var _ MyInt = Add(MyInt{1}, MyInt{2})
var _ MyFloat = Add(MyFloat{1}, MyFloat{2})

There are also a few other feature ideas at the end, for those interested 
(sum types, tuple types, unifying signatures and structures).

Here it is:

https://gist.github.com/willfaught/70f178ff52296d1865ae1f5ea0e574c4

-- 
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/efa7c07e-4a92-48b3-80e0-2820d1831ecan%40googlegroups.com.


Re: [go-nuts] Are the two constraints equivalent to each other?

2022-04-02 Thread tapi...@gmail.com
Ah, I forgot that point.
Thanks for the explanation!

On Saturday, April 2, 2022 at 10:00:27 PM UTC+8 axel.wa...@googlemail.com 
wrote:

> Ptr[int] is a defined type, `*int` is not. So the two types are not the 
> same and this is working as intended.
>
> On Sat, Apr 2, 2022 at 3:50 PM tapi...@gmail.com  
> wrote:
>
>>
>> package main
>>
>> type Ptr[E any] *E
>>
>> type MyConstraint interface {
>> Ptr[int]
>> }
>>
>> type YourConstraint interface {
>> *int
>> }
>>
>> func foo[T MyConstraint](x T) {
>> }
>>
>> func bar[T YourConstraint](x T) {
>> }
>>
>> func main() {
>> var x = new(int)
>> foo(x) // *int does not implement MyConstraint
>> bar(x)
>> }
>>
>> -- 
>> 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...@googlegroups.com.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/e252f550-b5ae-43ca-b25d-12ce076fd74cn%40googlegroups.com
>>  
>> 
>> .
>>
>

-- 
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/4f08c0cb-a03e-4de2-b59d-c8edffe42d52n%40googlegroups.com.


Re: [go-nuts] Are the two constraints equivalent to each other?

2022-04-02 Thread 'Axel Wagner' via golang-nuts
Ptr[int] is a defined type, `*int` is not. So the two types are not the
same and this is working as intended.

On Sat, Apr 2, 2022 at 3:50 PM tapi...@gmail.com 
wrote:

>
> package main
>
> type Ptr[E any] *E
>
> type MyConstraint interface {
> Ptr[int]
> }
>
> type YourConstraint interface {
> *int
> }
>
> func foo[T MyConstraint](x T) {
> }
>
> func bar[T YourConstraint](x T) {
> }
>
> func main() {
> var x = new(int)
> foo(x) // *int does not implement MyConstraint
> bar(x)
> }
>
> --
> 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/e252f550-b5ae-43ca-b25d-12ce076fd74cn%40googlegroups.com
> 
> .
>

-- 
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/CAEkBMfHEhpp2a0hv1Hq%3DEiyb9scLNNjrVr-YPZs9Y-0E8DG%2BkA%40mail.gmail.com.


[go-nuts] Are the two constraints equivalent to each other?

2022-04-02 Thread tapi...@gmail.com

package main

type Ptr[E any] *E

type MyConstraint interface {
Ptr[int]
}

type YourConstraint interface {
*int
}

func foo[T MyConstraint](x T) {
}

func bar[T YourConstraint](x T) {
}

func main() {
var x = new(int)
foo(x) // *int does not implement MyConstraint
bar(x)
}

-- 
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/e252f550-b5ae-43ca-b25d-12ce076fd74cn%40googlegroups.com.


Re: [go-nuts] Why is it forbidden to add methods to an existing type?

2022-04-02 Thread Brian Candler
Correct repository path is: https://github.com/jackc/pgtype

Interesting.  These structs generally contain a Status value as well:

type Int8 struct {
   Int int64
   Status Status
}

where pgtype.go has:

type Status byte

const (
   Undefined Status = iota
   Null
   Present
)

They also have Set() and Get() methods, although these are not 
compiled-time type safe as they accept and return interface{}

On Friday, 1 April 2022 at 17:40:42 UTC+1 sam.a@gmail.com wrote:

>
> Thanks for clarifying that, @Brian. Yeah. It took a bit to warm up to that 
> approach, but the github.com/jackc/pgtypes convinced me that the results 
> were worth it. The benefits:  A, package interpretation methods with a 
> piece of data, B, lazily valuate data when needed, and C, gain 
> introspective capability specific to the type and not using reflect
> On Friday, April 1, 2022 at 4:47:32 AM UTC-5 Brian Candler wrote:
>
>> That wasn't literal code with anglebrackets - you're supposed to fill 
>> that in yourself.  I think he meant something like:
>>
>> type fooString struct{ string }
>>
>> https://go.dev/play/p/4Q94xMZDciV
>>
>> What this is doing is *embedding* a string value into a struct; if you 
>> have not come across type embedding before then Google for the details.
>>
>> You still cannot use one of these types transparently as a string, but 
>> you can use
>> x.string
>> instead of
>> string(x)
>> to extract the value.
>>
>> On Friday, 1 April 2022 at 06:48:04 UTC+1 yan.z...@gmail.com wrote:
>>
>>> Hi Sam! Your solution does not seem to work:
>>>
>>> package main
>>>
>>> import(
>>> "fmt"
>>> "strconv"
>>> )
>>>
>>> type  String struct{string}
>>>
>>> func (s String) print(){
>>> fmt.Println(s)
>>> }
>>>
>>> func main() {
>>>var a String ="hello, world\n"
>>>
>>>a.print()
>>>
>>>fmt.Println(strconv.ParseInt("78",10, 64))
>>>
>>>var x String ="452"
>>>
>>>n, _ := strconv.ParseInt(x, 10, 64)
>>> }
>>>
>>> 在2022年3月26日星期六 UTC+8 06:41:15 写道:
>>>

 My workaround like is something like `type String 
 struct{string}. It can be reasonably treated as a string for most cases in 
 which as string is needed, and it lets you convert back conveniently from 
 any scope in which it's reasonable for your program to know the difference.
 On Friday, March 18, 2022 at 12:46:34 AM UTC-5 Henry wrote:

> My own preference is to have a small number of methods and put the 
> general functionalities into functions. By putting the general 
> functionalities into functions, you allow code reuse. In object-oriented 
> programming, you normally attach as many functionalities as possible to 
> their corresponding types and achieve code reuse via inheritance. Since 
> Go 
> does not have inheritance, you can achieve a similar effect with 
> standalone 
> functions. 
>
> On Friday, March 18, 2022 at 11:26:51 AM UTC+7 Ian Lance Taylor wrote:
>
>> On Thu, Mar 17, 2022 at 7:17 PM Zhaoxun Yan  
>> wrote: 
>> > 
>> > I just came across this taboo in golang - new methods cannot be 
>> added to an existing type: 
>>
>> Yes. If we didn't have this prohibition, then the set of interfaces 
>> satisfied by a type would depend on which package was using the type. 
>>
>> See the discussion at https://go.dev/issue/21401. 
>>
>> Ian 
>>
>

-- 
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/f73cf4b5-b3a0-4902-ac43-34ff06339ae5n%40googlegroups.com.