Bob Hutchison <
hutch-...@recursive.ca> writes:
> On 2012-06-26, at 9:03 PM, Ian Lance Taylor wrote:
>
>> 1) The Uniform Access Principle is a theory about how languages should
>> work. Is it a good idea in general? I don't know. Is it a good idea
>> for Go? No. The benefit is that the user of a type doesn't have to
>> care how some data is implemented. The drawback is that in real
>> programs, it matters. Go of course permits you to apply the UAP to your
>> own types, by always using methods. But it does not require you to do
>> so. If your framework will benefit from providing consistent access to
>> all fields, then implement them using a method.
>
> I'm not sure I buy the "real program" argument :-) What's different
> between a real program and a not real program?
The Uniform Access Principle is a theoretical idea. There are many such
theoretical ideas in language design. There are many programs written
in support of these theoretical ideas.
When I say a "real program" I simply mean a program written to solve a
real problem, rather than a program written to investigate a language.
>> 2) Go in general permits immutable structs: don't export the struct,
>> don't export its fields, provide methods to retrieve values but not
>> change them. For example, the reflect.Value type works this way. The
>> trick with immutability is keeping it out of the type system.
>
> If you don't export the struct what do you export? Surely not interface{}?
Well, I pointed you at reflect.Value as an example. Here is a somewhat
different trivial example inline:
type unexportedStructType {
val int
}
var ImmutableStruct = unexportedStructType{1}
func (p *ImmutableStruct) GetVal() int {
return p.val
}
Now another package can use ImmutableStruct.GetVal() to retrieve the
value of val, but that other package has no way to change val.
Go gives you control over visibility at several levels, so there are
other approaches you could take. Returning an interface would be one of
them. I don't see why it would be an interface{}--I think it would be
an interface with methods that let you pick up the values you want.
>> 3) Optional and default arguments would interact poorly with interfaces.
>
> I think it depends on how you treat them. The compiler has a lot of freedom, including, for example (with no real thought behind the suggestion) simply inserting the default values at the call point.
type I interface {
Lookup(name string, id int) *P
}
func (p *T1) Lookup(name string, id int) *P {
...
}
func (p *T2) Lookup(name string, id int = 2) *P {
...
}
func (p *T3) Lookup(name, string, id int, id2 int = 4) *P {
...
}
Clearly the type T1 satisfies the interface I. What about the types T2
and T3?
If we can have default arguments for type methods, can we have them for
interface methods as well?
It is possible to answer questions like this, but it means additional
complexity, it makes the language harder to understand, it makes
programs harder to understand. Is it worth it?
>> It's very simple and efficient that interface
>> methods are recognized only by name.
>
> Which, I think in Go, is equivalent to being recognised by signature. No?
Recognizing by name is much simpler than recognizing by signature. You
don't have to puzzle out the exact rules about type identity. You can
just look at the names.
>> 4) Unused errors. One of the issues with writing large programs is
>> eliminating cruft. Go keeps cruft down by design. It's a tradeoff.
>
> And in production I'll take what Go does anytime. The trouble is that
> five minutes where you're trying to work through some issue while
> developing.
It's true: Go is inflexible and eschews compiler options. We've seen
too many cases where an option is set "just during development" and is
never removed "because we don't have time now."
>> 5) Goroutine locals don't really make sense when goroutines are cheap.
>
> Hmm? Not sure what you mean here. Yes, cheap goroutines change a lot
> of things, and yes they can deal with some otherwise very complex
> situations very neatly (this is a *huge* part of why I started using
> Go in the first place). But I don't see how cheap goroutines change
> the sensibility of locals?
When I start a new goroutine, it no longer has the same set of goroutine
local variables. So adding a go statement is no longer purely
introducing concurrency into the program; it is also changing the
meaning of variables. The same problem exists for thread local
variables, but because creating a new thread is a relatively expensive
operation, people don't notice it.
>> 6) I'm not sure how I feel about weak references. Perhaps there would
>> be a reasonable way to add them. I don't think they should go into the
>> type system, though. And to be useful they should really go into slices
>> and maps, but then the complexity increases.
>
> I have no doubt that in Go the compiler's complexity increases. I
> think it's worth spending some time trying to express them in Go in a
> way reasonable to developers and feasible for implementation.
I'm not talking about the complexity of the compiler. I'm talking about
the complexity of understanding the language, and programs written in
the language.
Ian