What does ... mean when coming directly after a slice? - go

What does ... mean in this context in Go?
ids = append(ids[:index], ids[index+1:]...)
I have read this great Q&A:
Do three dots (which is called wildcard?) contain multiple meanings?
about what ... means in some situations, but I don't understand what it means in the situation above.

Some languages (C, Python, ...) accept variadic arguments. Basically, you allow the client of a function to pass a number of arguments, without specifying how many. Since the function will still need to process these arguments one way or another, they are usually converted to a collection of some sort. For instance, in Python:
def foo(x, *args): # * is used for variadic arguments
return len(args)
>>> foo(1) # Passed the required argument, but no varargs
0
>>> foo(1, 2, 3) # Passed the required, plus two variadic arguments
2
>>> foo(1, 2, 3, 4, 5, 6) # required + 5 args, etc...
5
Now one obvious problem of that approach is that a number of arguments is quite a fuzzy concept as far as types are concerned. C uses pointers, Python doesn't really care about types that much in the first place, and Go takes the decision of restricting it to a specified case: you pass a slice of a given type.
This is nice because it lets the type-system do its thing, while still being quite flexible (in particular, the type in question can be an interface, so you can pass different 'actual types' as long as the function knows how to process these.
The typical example would be the Command function, which executes a program, passing it some arguments:
func Command(name string, arg ...string) *Cmd
It makes a lot of sense here, but recall that variadic arguments are just a convenient way to pass slices. You could have the exact same API with:
func Command(name string, args []string) *Cmd
The only advantage of the first is that it lets you pass no argument, one argument, several... without having to build the slice yourself.
What about your question then ?
Sometimes, you do have a slice, but need to call a variadic function. But if you do it naively:
my_args_slice := []string{"foo", "bar"}
cmd := Command("myprogram", my_args_slice)
The compiler will complain that it expects string(s), but got a slice instead ! What you want to tell it is that it doesn't have to 'build the slice in the back', because you have a slice already. You do that by using this ellipsis:
my_args_slice := []string{"foo", "bar"}
cmd := Command("myprogram", my_args_slice...) // <- Interpret that as strings
The append function, despite being built-in and special, follows the same rules. You can append zero, one, or more elements to the slice. If you want to concatenate slices (i.e. you have a 'slice of arguments' already), you similarly use the ellipsis to make it use it directly.

It unpacks slice.
ids[:index] is a short form of ids[0:index]
ids[index+1:] is a short form of ids[index+1:len(ids)-1]
So, your example ids = append(ids[:index], ids[index+1:]...) translates to
//pseudocode
ids = append(ids[0:index], ids[index+1], ids[index+2], ids[index+3], ..., ids[len(ids)-2], ids[len(ids)-1])

Related

Is there a way to map an array of objects in golang?

Coming from Nodejs, I could do something like:
// given an array `list` of objects with a field `fruit`:
fruits = list.map(el => el.fruit) # which will return an array of fruit strings
Any way to do that in an elegant one liner in golang?
I know I can do it with a range loop, but I am looking for the possibility of a one liner solution
In Go, arrays are inflexible (because their length is encoded in their type) and costly to pass to functions (because a function operates on copies of its array arguments). I'm assuming you'd like to operate on slices rather than on arrays.
Because methods cannot take additional type arguments, you cannot simply declare a generic Map method in Go. However, you can define Map as a generic top-level function:
func Map[T, U any](ts []T, f func(T) U) []U {
us := make([]U, len(ts))
for i := range ts {
us[i] = f(ts[i])
}
return us
}
Then you can write the following code,
names := []string{"Alice", "Bob", "Carol"}
fmt.Println(Map(names, utf8.RuneCountInString))
which prints [5 3 5] to stdout (try it out in this Playground).
Go 1.18 saw the addition of a golang.org/x/exp/slices package, which provides many convenient operations on slices, but a Map function is noticeably absent from it. The omission of that function was the result of a long discussion in the GitHub issue dedicated to the golang.org/x/exp/slices proposal; concerns included the following:
hidden cost (O(n)) of operations behind a one-liner
uncertainty about error handling inside Map
risk of encouraging a style that strays too far from Go's traditional style
Russ Cox ultimately elected to drop Map from the proposal because it's
probably better as part of a more comprehensive streams API somewhere else.

Confused about why hashsum, encode, print is different then write, hashum, encode, print in Go?

Sorry about the title. I couldn't come up with a better way of phrasing my question and will change it happily if somebody else can.
Hasher is defined with
hasher := md5.New()
Anyway, I am curious why this:
fmt.Println(hex.EncodeToString(hasher.Sum([]byte(input))))
gives me 6869d41d8cd98f00b204e9800998ecf8427e, while this:
hasher.Write([]byte(input))
fmt.Println(hex.EncodeToString(hasher.Sum(nil))
gives me 49f68a5c8493ec2c0bf489821c21fc3b
and this:
fmt.Printf("%x\n", md5.Sum([]byte(input)))
gives me 49f68a5c8493ec2c0bf489821c21fc3b.
Generally hasher.Sum() does not hash the passed slice. The passed slice is used as the destination: it appends the current hash to it and does not change the underlying hash state. hasher.Write() obviously includes the passed slice in the hash calculation. The 2 examples are fundamentally different, the different results are nothing but expected.
Always read the documentation. hash.Hash.Sum():
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte
So when you first call hasher.Sum(), whatever you pass to it, it doesn't matter in terms of the result hash. If you haven't written anything into hasher previously, you'll see the initial hash.
When you next call hasher.Write([]byte(input)), you'll write the bytes of input into the hasher, so when you call hasher.Sum(nil) next, you'll see the calculated hash of input. Since you pass nil, a new slice will be allocated to accommodate the result.
When you again call hasher.Write([]byte(input)), as previously written: this won't change the hash state, the passed slice is not used as input, but only as the destination for "returning" the result, the current hash value. So you will get the same hash value as you got from the previous hasher.Sum(nil) call. Obviously, if the passed slice does not have enough capacity to store the result, a new one will be allocated / used.
See this complete, runnable example which reproduces your output:
input := "hi"
hasher := md5.New()
fmt.Println(hex.EncodeToString(hasher.Sum([]byte(input))))
hasher.Write([]byte(input))
fmt.Println(hex.EncodeToString(hasher.Sum(nil)))
fmt.Printf("%x\n", md5.Sum([]byte(input)))
Try it on the Go Playground.

What does `append()...` do in Go

I have this Go code
kithttp.NewServer(
endpoints.AuthorizeUserEndpoint,
decodeRequest,
encodeResponse,
append(options, httptransport.ServerBefore(opentracing.FromHTTPRequest(tracer, "calling HTTP POST /endpoint", logger)))...,
)
Could you explain me what does append()... do with ... in the end.
The append built-in function appends elements to the end of a slice.
Read more in the docs.
The ... is used in variadic functions (of which append is an example), to pass all of the elements of the preceding variable.
So given a variable x := []int{1, 2, 3}, the expression foo(x...) will pass it to a function as if you had called foo(1, 2, 3) in contrast to foo(x) which would equivalent to foo([]int{1, 2, 3}).
Basically append takes the options slice, appends additional options to it, returns new slice and then this merged slice is passed as separate arguments to kithttp.NewServer constructor thanks to ....

Kotlin asterisk operator before variable name or Spread Operator in Kotlin

I want to know what exactly an asterisk does before a variable name in Kotlin.
I saw this (*args) in a Spring boot Kotlin example:
#SpringBootApplication
open class Application {
#Bean
open fun init(repository: CustomerRepository) = CommandLineRunner {
repository.save(Customer("Jack", "Bauer"))
repository.save(Customer("Chloe", "O'Brian"))
repository.save(Customer("Kim", "Bauer"))
repository.save(Customer("David", "Palmer"))
repository.save(Customer("Michelle", "Dessler"))
}
}
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
The * operator is known as the Spread Operator in Kotlin.
From the Kotlin Reference...
When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *):
It can be applied to an Array before passing it into a function that accepts varargs.
For Example...
If you have a function that accepts a varied number of arguments...
fun sumOfNumbers(vararg numbers: Int): Int {
return numbers.sum()
}
Use the spread operator to pass an array's elements as the arguments:
val numbers = intArrayOf(2, 3, 4)
val sum = sumOfNumbers(*numbers)
println(sum) // Prints '9'
Notes:
The * operator is also the multiplication operator (of course).
The operator can only be used when passing arguments to a function. The result of the operation cannot be stored since it yields no value (it is purely syntactic sugar).
The operator may confuse some C/C++ programmers at first because it looks like a pointer is being de-referenced. It isn't; Kotlin has no notion of pointers.
The operator can be used in-between other arguments when calling a vararg function. This is demonstrated in the example here.
The operator is similar to the apply function in various functional programming languages.
In addition to the answers that were directly towards "what is this thing!?!", you often have the case where you have a List and want to pass it to a function that is expecting a vararg. For this, the conversion is:
someFunc(x, y, *myList.toTypedArray())
Assuming that last parameter of someFunc is vararg of the same type as the elements in the list.
As described in the documentation this is a spread operator:
When we call a vararg-function, we can pass arguments one-by-one, e.g.
asList(1, 2, 3), or, if we already have an array and want to pass its
contents to the function, we use the spread operator (prefix the array
with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
In Java you can pass an array as is but an advantage of unpacking an array with spread operator * is that spread operator lets you combine the values from an array and some fixed values in a single call. Java doesn't support this.
If a function which accept a vararg(Variable number of arguments) parameter like:
fun sum(vararg data:Int)
{
// function body here
}
Now to call this method, we can do:
sum(1,2,3,4,5)
But what if we have these value in an array, like:
val array= intArrayOf(1,2,3,4,5)
then, to call this method we have to use spread operator, like:
sum(*array)
Here, *(spread operator) will pass all content of that array.
*array is equivalent to 1,2,3,4,5
But wait a minute, what if we call it like this: sum(array)
it will give us Type Mismatch compile time error:
Type mismatch.
Required:Int
Found:IntArray
The problem is sum function accept a vararg Int parameter(which accept value like: 1,2,3,4,5) and if we pass array, it will be passed as IntArray.

mixing "exploded" slices and regular parameters in variadic functions

I'm wondering why it's not possible to do the following in go:
func main() {
stuff := []string{"baz", "bla"}
foo("bar", stuff...)
}
func foo(s ...string) {
fmt.Println(s)
}
In my understanding, slice... "explodes" the slice so it can be used for multi argument function calls. So the above example should actually expand to foo("bar", "baz", "bla").
foo(stuff...) works as expected, no surprises here, but in the example above, the compiler complains about too many arguments.
Is this a desired limitation? I'm coming from a ruby background where a foo("bar", *stuff) is perfectly fine (and is, at least in my book, the same thing), that's why this surprises me.
The value for a variadic argument can be specified either by enumerating the elements, or using an existing slice, specified by its name followed by ....
You want to mix the 2 possible ways which is not permitted by the Go Language Specification (Passing arguments to ... parameters).
If the first form is used (enumerating the elements):
The value passed [as the variadic parameter] is a new slice of type []T with a new underlying array whose successive elements are the actual arguments.
If the latter is used (passing an existing slice followed by ...) no new slice is created, the one you pass is used as is. And the passed slice can only be used to specify the value of one – the final – variadic parameter. Attempting to pass both a single element and a slice will not match the signature (the parameter list in this case) of your function and you'll get an error:
too many arguments in call to foo
There is no actual "exploding" involved in Go, the term is just used in other languages to help visualize that the passed array or slice will not be an element of the variadic parameter but will be the value of variadic parameter itself.
Mixing the 2 would require to allocate a new slice because obviously the existing slice cannot be used.
The ugly way to get this to work is make it into a new variadic.
foo(append([]string{"bar"}, stuff...)...)
And if the order doesn't matter:
foo(append(stuff, "bar")...)
https://play.golang.org/p/mY6y0vScfPB
The specification on this is at the "Passing arguments to ... parameters":
If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T.
If f is invoked with no actual arguments for p, the value passed to p is nil.
Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.
In your case, where stuff... works:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
But "bar", stuff... doesn't match either case specified above.
T, []T doesn't match f([]T).
I ran into this situation when preparing arguments to feed to external commands. If possible, just build an one argument slice, then you don't have to worry about combining scalars with slices when it's time to call the function:
package main
import "os/exec"
func main() {
stuff := []string{"bar"}
stuff = append(stuff, "baz", "bla")
exec.Command("name", stuff...).Run()
}

Resources