Either one is fine, they both generate the same code, it depends on
what you're trying to communicate.
>
> (2) What is the canonical way to concatenate arrays? At the moment I
> use:
>
> func stringConcatenate(x, y []string) []string {
> result := make([]string, len(x) + len(y))
> i := 0
> for ; i < len(x); i++ {
> result[i] = x[i]
> }
> for j := 0; i < len(x) + len(y); i++ {
> result[i] = y[j]
> j++
> }
> return result
> }
The container/vector package has functions to handle that.
StringVector.InsertVector() is what you want.
> (3) Why are there no methods for strings? Right now I'm writing things
> like:
>
> if strings.HasSuffix(s, ".go") { ... }
>
> whereas
>
> if s.HasSuffix("go") { ... }
>
> seems nicer.
None of the base types have methods on them.
This is intentional to prevent issues with interfaces.
i.e base types don't satisfy any interfaces(except for the empty interface)
You can put methods on strings by defining a new type that is a string
and putting methods on that.
eg.
type mystring string;
func (*mystring) HasSuffix(string){}
> (4) Why is there no support for default arguments?
Default arguments make method dispatch complicated and make it easy to
make mistakes when calling methods.
eg. giving the wrong number of arguments to a method and not knowing.
- jessta
--
=====================
http://jessta.id.au
On Tue, 28 Sep 2010 19:56:34 +1000
Jessta <jes...@jessta.id.au> wrote:
> On Tue, Sep 28, 2010 at 7:27 PM, Mark <li...@qtrac.plus.com> wrote:
> > Hi,
> >
> > I've read most of the Go documentation & started to experiment with
> > Go, but haven't yet found answers to the following questions.
[snip]
>
> The container/vector package has functions to handle that.
> StringVector.InsertVector() is what you want.
Thanks. So to concatenate two strings, I'd do:
a := []string{"one", "two", "three"}
b := []string{"four", "five"}
var c vector.StringVector
av := vector.StringVector(a)
bv := vector.StringVector(b)
c.AppendVector(&av)
c.AppendVector(&bv)
Or is there a nicer way?
> > (3) Why are there no methods for strings? Right now I'm writing
> > things like:
> >
> > if strings.HasSuffix(s, ".go") { ... }
> >
> > whereas
> >
> > if s.HasSuffix("go") { ... }
> >
> > seems nicer.
>
> None of the base types have methods on them.
> This is intentional to prevent issues with interfaces.
> i.e base types don't satisfy any interfaces(except for the empty
> interface)
>
> You can put methods on strings by defining a new type that is a string
> and putting methods on that.
> eg.
> type mystring string;
> func (*mystring) HasSuffix(string){}
Sure, but is there an extra cost in doing this? And will Go end up with
lots of people creating their own mystrings (rather like the way people
typedef in C to get their own data type aliases)?
> > (4) Why is there no support for default arguments?
>
> Default arguments make method dispatch complicated and make it easy to
> make mistakes when calling methods.
> eg. giving the wrong number of arguments to a method and not knowing.
I'm not convinced by your second reason since Go supports ... arguments.
However, I can see that it would be more complicated to support default
arguments.
Thanks!
--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy
"Rapid GUI Programming with Python and Qt" - ISBN 0132354187
http://www.qtrac.eu/pyqtbook.html
I've always considered relatively liberal custom typedefing to be a
pretty good C/C++ practice. It's a very thin layer with no
computational cost, and often vastly improves code readability and
maintainability. Is there some seminal "Typedef Considered Harmful"
paper I haven't seen?
> Default arguments make method dispatch complicated
How? I can understand this when methods might be overloaded,
and argument types and/or their presence might make a difference,
but in Go when you see x.f(y) or f(z) you know what method it
is without having to look at y or z (you do need the type of x).
If that method is declared with default arguments, apply those
to the actual argument list. Dispatch doesn't, as far as I can see,
come into it.
> and make it easy to
> make mistakes when calling methods.
> eg. giving the wrong number of arguments to a method and not knowing.
That's what unit tests are for.
(Myself, I find that I can easily be confused when two arguments,
especially adjacent arguments, have the same type and there's
no (or two!) natural orders; I don't get x and y confused, but I can
get row and column confused -- which naturally comes first?)
Chris
--
Chris "allusive" Dollin
that would probably be something in favor of named arguments (or keyword
arguments):
Frobnicate(row=2, col=3)
or, to better match go's look'n'feel:
Frobnicate(row:2, col:3)
one can already achieve that kind of stuff with structs, but it is a bit
convoluted:
//---
package main
type arg struct {
col int
row int
}
func Frobnicate(a arg) {
println("col:", a.col)
println("row:", a.row)
}
func main() {
Frobnicate(arg{col:2, row:3})
Frobnicate(arg{2,3})
Frobnicate(arg{row:2, col:3})
return
}
/* EOF */
if all this scaffolding could somehow be done for us, that would help
code readability.
cheers,
sebastien.
Welcome to the Go community! =D
On 28 September 2010 19:27, Mark <li...@qtrac.plus.com> wrote:
> (1) What is the canonical way to test for an empty string?
Depending on context one way may be clearer, but they're essentially
the same. The idiom used in the Go standard libraries is s == "".
> (2) What is the canonical way to concatenate arrays?
You're on the right track. To concatenate two slices efficiently, you
should use the built-in copy function:
func concat(a, b []string) []string {
c := make([]string, len(a) + len(b))
copy(c[:len(a)], a)
copy(c[len(a):], b)
return c
}
You would also use copy to grow a slice, should it run out of
capacity. (ie, make a new slice and copy the contents of the old one
to the new one)
The vector package is often useful, but never essential. You should
certainly experiment with raw slices and copying to get a feel for
their power and efficiency.
> (3) Why are there no methods for strings? Right now I'm writing things
> like:
> if strings.HasSuffix(s, ".go") { ... }
> whereas
> if s.HasSuffix("go") { ... }
> seems nicer.
It seems nicer, sure. But what is the benefit? A small syntactical
bonus, maybe, but it comes with a complexity penalty. Strings are a
primitive type, and methods cannot be defined on primitive types (only
on named, user-defined types).
You could always create your own string type
type String string
and then define a bunch of helper methods on that. You'll find that in
practice it doesn't really matter.
> (4) Why is there no support for default arguments?
It would add complexity to the language, without much gain. If your
function takes enough arguments that defaults become essential, you
might be better off restructuring your code.
The flavour of my last two answers gives you an idea of the design
philosophy behind Go. It is a very simple language. Its features are
easy to understand, and predictable when combined. As a result,
newcomers often wonder why obvious things like this aren't included.
The answer is usually because we thought long and hard about it, and
it just wasn't worth the complexity.
This tends to be Go's most underrated property, as it takes time to
understand its tangible benefits.
> (5) I use the syntax/go.vim file and that's great; but there's no
> indent/go.vim file so vim doesn't handle autoindentation properly
> (esp. when you enter a colon). I tried the unofficial one that's on
> the Go web site but it doesn't work well.
When is indentation necessary after a colon? When you're writing a
struct literal? Eg:
t := MyStruct{
Element: "value",
OtherElement: 12,
}
I use Vim myself, but I haven't felt the need for that particular
feature. This is because Go comes with "gofmt", a command-line program
that reformats Go code with the standard formatting rules. It
automatically aligns and indents everything. After using it for
awhile, one tends to get used to writing lazily and having gofmt clean
it up. (or the reverse, where you get so used to the standard style
that running gofmt is a no-op ;-)
In Vim, you can run gofmt on the current buffer with this command
(without quotes) ":%!gofmt".
Andrew
Thanks:-) { actually I've been lurking a while }
> On 28 September 2010 19:27, Mark <li...@qtrac.plus.com> wrote:
> > (1) What is the canonical way to test for an empty string?
>
> Depending on context one way may be clearer, but they're essentially
> the same. The idiom used in the Go standard libraries is s == "".
Good, that looks nicer.
> > (2) What is the canonical way to concatenate arrays?
>
> You're on the right track. To concatenate two slices efficiently, you
> should use the built-in copy function:
>
> func concat(a, b []string) []string {
> c := make([]string, len(a) + len(b))
> copy(c[:len(a)], a)
> copy(c[len(a):], b)
> return c
> }
>
> You would also use copy to grow a slice, should it run out of
> capacity. (ie, make a new slice and copy the contents of the old one
> to the new one)
>
> The vector package is often useful, but never essential. You should
> certainly experiment with raw slices and copying to get a feel for
> their power and efficiency.
I'm used to Python lists, but in Python you can use + and += on them, so
I wasn't really sure how to do that in Go... but I can see how now that
you've shown me the above.
> > (3) Why are there no methods for strings? Right now I'm writing
> > things like:
> > if strings.HasSuffix(s, ".go") { ... }
> > whereas
> > if s.HasSuffix("go") { ... }
> > seems nicer.
>
> It seems nicer, sure. But what is the benefit? A small syntactical
> bonus, maybe, but it comes with a complexity penalty. Strings are a
> primitive type, and methods cannot be defined on primitive types (only
> on named, user-defined types).
>
> You could always create your own string type
> type String string
> and then define a bunch of helper methods on that. You'll find that in
> practice it doesn't really matter.
Since strings will be used an awful lot I suspect that many Go
programmers will end up creating their own (slightly different) String
types purely for that convenience. Since the Go library already has
container/vector for StringVector as a convenience over []string it
seems to me that it would make sense to have say, a strings.String type
as a convenience over string.
> > (4) Why is there no support for default arguments?
>
> It would add complexity to the language, without much gain. If your
> function takes enough arguments that defaults become essential, you
> might be better off restructuring your code.
>
> The flavour of my last two answers gives you an idea of the design
> philosophy behind Go. It is a very simple language. Its features are
> easy to understand, and predictable when combined. As a result,
> newcomers often wonder why obvious things like this aren't included.
> The answer is usually because we thought long and hard about it, and
> it just wasn't worth the complexity.
>
> This tends to be Go's most underrated property, as it takes time to
> understand its tangible benefits.
Sure; I think one consequence will be people using wrappers:
func mycomplexfn(a, b, c, d string) {...}
func mycomplexfn2(a, b string) { mycomplexfn(a, b, "foo", "bar") }
etc.
Which is fine of course.
> > (5) I use the syntax/go.vim file and that's great; but there's no
> > indent/go.vim file so vim doesn't handle autoindentation properly
> > (esp. when you enter a colon). I tried the unofficial one that's on
> > the Go web site but it doesn't work well.
>
> When is indentation necessary after a colon? When you're writing a
> struct literal? Eg:
>
> t := MyStruct{
> Element: "value",
> OtherElement: 12,
> }
This is where I get bitten: I start typing in a new function:
func myfunc(arg string) {
x :
^as soon as I press colon the line gets shifted left (my guess is
that vim thinks it is going to be a label)
so then I complete what I was typing and have to shift right, e.g.
x := baz()
which is irritating.
> I use Vim myself, but I haven't felt the need for that particular
> feature. This is because Go comes with "gofmt", a command-line program
> that reformats Go code with the standard formatting rules. It
> automatically aligns and indents everything. After using it for
> awhile, one tends to get used to writing lazily and having gofmt clean
> it up. (or the reverse, where you get so used to the standard style
> that running gofmt is a no-op ;-)
I'm fine with using gofmt, but it would be nice to have vim indent
correctly as I type---just like it does when I write in any other
lanugage I use.
> In Vim, you can run gofmt on the current buffer with this command
> (without quotes) ":%!gofmt".
Point taken; but still be nicer if vim just did it right in the first
place.
Thanks!
--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy
"Advanced Qt Programming" - ISBN 0321635906
http://www.qtrac.eu/aqpbook.html
I doubt it. And I agree with you that typedefs are v. useful esp. for
insulating code from different sized ints etc.
However, heavy use of typedefs can make code much harder to get into,
and for something so fundamental as strings I think it would be a pity
if lots of different Go programmers ended up with their own slightly
different String types.
--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy
"Programming in Python 3" - ISBN 0321680561
http://www.qtrac.eu/py3book.html
And there is always s + "badgerbadgerbadger" == "badgerbadgerbadger".
http://groups.google.com/group/golang-nuts/msg/2e321a2e6db42ead
Russ
As you can see, Go requires you to be explicit when making
allocations. The vector package provides support for Python-like
managed lists.
> Since strings will be used an awful lot I suspect that many Go
> programmers will end up creating their own (slightly different) String
> types purely for that convenience.
That's not been my observation so far. It's way easier to just type
"strings." than to implement the wrapper (and convert to and from the
named type when interfacing with other code). Only if you were doing
custom string processing would it really pay off.
> Since the Go library already has
> container/vector for StringVector as a convenience over []string it
> seems to me that it would make sense to have say, a strings.String type
> as a convenience over string.
I use both in different settings. More often than not, all you want is
a plain old slice.
> This is where I get bitten: I start typing in a new function:
>
> func myfunc(arg string) {
> x :
> ^as soon as I press colon the line gets shifted left (my guess is
> that vim thinks it is going to be a label)
That does indeed sound broken. Do you know much about Vim's
smartindent configuration? (I don't.) If you do, would you please fix
it and submit a patch? (or maybe other Vim wizards that are reading
can help...)
http://golang.org/doc/contribute.html
> Point taken; but still be nicer if vim just did it right in the first
> place.
For sure.
Cheers,
Andrew
On Wed, 29 Sep 2010 09:34:40 +1000
Andrew Gerrand <a...@golang.org> wrote:
[snip]
> > This is where I get bitten: I start typing in a new function:
> >
> > func myfunc(arg string) {
> > x :
> > ^as soon as I press colon the line gets shifted left (my
> > guess is that vim thinks it is going to be a label)
>
> That does indeed sound broken. Do you know much about Vim's
> smartindent configuration? (I don't.) If you do, would you please fix
> it and submit a patch? (or maybe other Vim wizards that are reading
> can help...)
> http://golang.org/doc/contribute.html
[snip]
I don't know enough about programming vim unfortunately. Also, it is
even more broken because even after you shift right when you hit Enter
to go to the next line it is wrongly indented.
So I hope a Vim guru will help here!
A temporary fix might be to turn smartindent off with ":set nosmartindent"
Andrew
As far as I can tell Go has no explicit support for static data in
functions---or have I just missed seeing it?
My use cases are (1) when I have pure functions that contain expensive
computations and I want to keep a local cache of results inside them and
(2) when I have a lot of data in the function that I don't want to
recreate on every call.
At the moment I'm solving this by using closures along these lines:
var MyFunc func(x)y = makeMyFunc()
func makeMyFunc() func(x)y
staticData := ...
return func(x)y {
... // uses the staticData
}
}
Is this the correct idiom for static data inside functions in Go?
Thanks!
PS I've finished my first Go program < 200 lines called "onego". Here's
its -help:
-------
usage: onego single_file_program1.go [single_file_program2.go [...]]
-or- onego single_file_program1.go [arg1 [arg2 [...]]]
If multiple files are given they are all built; if one file is given it
is built and run and given any arguments that are passed.
-------
I've found this v. useful for creating lots of small single-file test
programs in the same directory to help me learn Go since to build & run
each time I just do:
$ onego myprog.go
without needing to bother creating makefiles.
If this would be of any use to anyone else I'll happily send it to
you---it is a single .go file of course:-)
--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy
I would just use an unexported package-scope variable and mutter behind my
teeth about scope versus extent.
On Wed, 29 Sep 2010 18:00:49 +1000
Andrew Gerrand <a...@golang.org> wrote:
> On 29 September 2010 17:54, Mark Summerfield <li...@qtrac.plus.com>
> wrote:
> > Hi,
> >
> > As far as I can tell Go has no explicit support for static data in
> > functions---or have I just missed seeing it?
> >
> > My use cases are (1) when I have pure functions that contain
> > expensive computations and I want to keep a local cache of results
> > inside them and (2) when I have a lot of data in the function that
> > I don't want to recreate on every call.
> >
> > At the moment I'm solving this by using closures along these lines:
[snip]
> > Is this the correct idiom for static data inside functions in Go?
>
> The more idiomatic way:
>
> --
>
> package foo
>
> var staticData = preCalc()
>
> func preCalc() int {
> // do something expensive
> return // result
> }
>
>
> func Bar() {
> // use staticData
> }
>
> --
>
> Both preCalc and staticData are package-private; only Bar is visible
> outside.
Yes, I love Go's really nice approach to private/Public.
> Also, check out sync.Once; that will allow you to only do the
> expensive initialisation when Bar() is called for the first time.
I'm still working my way through the pkg docs!
Your idiom is fine for use case (2), but that doesn't help use case (1),
i.e., if you want a local cache that's populated on the fly.
For example: if you're doing lots of string slicing (by character) and
are mostly using the same strings. This involves converting string to
[]int and back all the time. So I came up with this:
var RunesForString func(string)([]int) = makeRunesForStringFunction()
var MaxRunesCacheSize int = 255
func makeRunesForStringFunction() func(string)([]int) {
cache := make(map[string][]int)
return func(s string) (runes []int) {
runes, ok := cache[s]
if !ok {
runes = []int(s)
cache[s] = runes
}
if len(cache) > MaxRunesCacheSize {
cache = make(map[string][]int)
}
return
}
}
I'm happy with this, but want to be sure that I'm doing things in the
most idomatically correct way.
Thanks!
--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy
Just create a type which holds that data, and methods that act on it.
This will also let you put a mutex in there to guard the map from
being corrupted by concurrent access.
--
package main
import (
"fmt"
"sync"
)
type RuneCache struct {
cache map[string][]int
mu sync.Mutex
}
func NewRuneCache() *RuneCache {
return &RuneCache{cache: make(map[string][]int)}
}
func (rc *RuneCache) Runes(s string) []int {
rc.mu.Lock()
defer rc.mu.Unlock()
runes, ok := rc.cache[s]
if !ok {
runes = []int(s)
rc.cache[s] = runes
}
return runes
}
func main() {
rc := NewRuneCache()
fmt.Println(rc.Runes("abcd"))
}
--
I think this is a lot clearer than using the closure, plus it lets you
add functionality more easily.
As an aside, one thing that might be of relevance to you is
utf8.String (available in this week's forthcoming release), which
permits reasonably efficient indexing of strings by rune. Depending on
your use case, it could offer significant efficiency benefits over
converting each string to []int.
Andrew
as far as i can see, the above code is functionally identical
to this, which is more conventional:
var cache = make(map[string][]int)
func RunesForString(s string) []int {
const MaxRunesCacheSize = 255
runes, ok := cache[s]
if !ok {
runes = []int(s)
cache[s] = runes
}
if len(cache) > MaxRunesCacheSize {
cache = make(map[string][]int)
}
return runes
}
i can see that in some cases, you might want to have
some persistent state for a function that isn't global
(for instance, say you wanted the ability to have
several different caches of different maximum sizes)
in that case you could go with the way you were using,
but it would probably be more idiomatic to define the
function as a method on a type that holds the data.
this has the advantage is that it's easier to debug - you
can easily print out the cache contents if needed.
for instance:
type Cache struct {
maxSize int
cache map[string][]int
}
func (c *Cache) RunesForString(s string) []int {
...
}
of course with all these methods, you have to be careful about
concurrent access - it's worth wrapping the map access in a sync.Mutex.
or if it's really one time, use sync.Once.
russ
On Wed, 29 Sep 2010 20:29:38 +1000
Andrew Gerrand <a...@golang.org> wrote:
> On 29 September 2010 19:52, Mark Summerfield <li...@qtrac.plus.com>
> wrote:
> > For example: if you're doing lots of string slicing (by character)
> > and are mostly using the same strings.
> > I'm happy with this, but want to be sure that I'm doing things in
> > the most idomatically correct way.
>
> Just create a type which holds that data, and methods that act on it.
> This will also let you put a mutex in there to guard the map from
> being corrupted by concurrent access.
Thanks for this---and thanks to to Roger & Russ for their ideas.
I clearly also need to spend some time reading the pkg docs:-)
[snip]
> As an aside, one thing that might be of relevance to you is
> utf8.String (available in this week's forthcoming release), which
> permits reasonably efficient indexing of strings by rune. Depending on
> your use case, it could offer significant efficiency benefits over
> converting each string to []int.
I look forward to that!
--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy