I'm not familiar with the actual implementation, but I guess using a node
based adressing system would slow access down the bigger the map is. And
speed is one of the main arguments for using a map, isn't it?
Also, what's so bad with using *T?
I do see your point, that this is in fact somewhat counter-intuitive,
but you can seldom have it both ways, intuitive and efficient.
In my opinion, Go has reached an unmatched level being intuitive and
still keeping the binaries efficient (and this being a system
programming language, the focus is without doubt on effiency).
Surma
the easiest solution is just to use either T everywhere or
*T everywhere. if B has no side effects, then it could be
a method on T without loss of generality.
as for the constructor A, i quite like this pattern:
func (t *T) A() *T {
t.foo = 3
t.bar = "hello"
return t
}
that way you get to choose whether to use T or *T.
e.g.
N[i] = new(T).A()
vs.
(&somestruct.t).A()
I'm confused as to what situations having A() return a *T wouldn't
make sense. Could you give an example?
--
David Roundy
what purpose did you have in making
your method take a pointer receiver?
if you gave it a value receiver you'd be
able to call it on a map index expression
just fine.
russ
Because programming is about solving problems, and you failed to
describe one, and instead just described what you wanted to do. If
you want useful advice, you need to describe your problem with
sufficient accuracy that we can understand why the natural go-like
solution doesn't make sense for you.
--
David Roundy
This has already been answered (by stev...@gmail.com).
Russ
Russ
> I don't believe so. In fact, reading through $(GOROOT)/src/pkg/runtime/
> hashmap.c, I found hash entries are composed of a "hash_hash_t" called
> "hash" and a "byte[1]" called "data". Both of these are pointer types.
The data field is not a pointer type. The struct is allocated such that
the data array is large enough to hold the data. The code allocates
groups of elements which act as a closed hash table. When the hash
table grows, elements do indeed move around.
I agree that it is odd that map index expressions can appear on the left
hand side of an assignment but their address can not be taken (that is
also true of the blank identifier "_"). However, as others have noted,
permitting taking the address of a map index expression would be
tantamount to requiring all implementation of map[K]V to become
map[K]*V. That does not seem desirable.
Ian
> I think
> the main reason you find this change undesirable is because of the
> implementation you have chosen to use for the moment.
I think it's a little deeper than that. It's because I think the
natural implementation for map is a hash table. While you're right that
Go could use a different data structure, I think the different
performance characteristics would be problematic in themselves.
Note that taking the address of a map element is interesting to consider
with regard to modifications of the map. If a is an array or slice, and
I take the address of a[5], and then I change a[5], it's clear that the
value I see through the pointer should change similarly. It's also
clear that that should be true if I change a[6] and then change a[5].
In fact, the value will always be consistent unless I change a itself.
Presumably, if you could take the address of a map element, we would
want to the same rules to apply. If I take the address of m["a"], then
changing m["b"] should not affect that, even if "b" were not previously
in the map. If you extend that to large numbers of insertions, I wonder
whether you can really come up with a data structure which supports that
without making m["a"] be a pointer.
> But the reason I ask for this change still has nothing to do with the
> underlying container. Whether or not this restriction is made should
> be a design decision. When making this decision, there should be
> thought as to whether or not it's overly difficult to implement. It's
> not. There should be thought as to whether the performance will suffer
> greatly. It won't. Past that point in making this decision, there
> should be no further scrutinizing of the underlying structure to make.
I think you've correctly identified the tradeoffs. However, I don't
think I'm with you in concluding that the performance issue is
negligible. Making every map insertion requires allocating a new memory
object is definitely a performance cost. Is it worth paying the cost to
get a bit more orthogonality in the language? Perhaps. But for me it's
not an obvious decision.
> Or think about arrays and slices. If you could change their
> implementation to some theoretical implementation that would yield
> some negligible benefit, but would preclude their indexing from being
> addressable, would you do it?
I would consider it, yes.
Ian
I agree, but would also want to emphasize that raw memory use is an
important consideration as well. Storing an extra pointer for each
element seems liable to dramatically increase the total size of a map
(e.g. for map[int]int with 64 bit pointers and 32 bit ints), which is
a serious issue. True, it's hard to predict just how big this
increase will be, but I'd prefer that the language not make a choice
that precludes the use of more efficient data structures. For
instance, I could imagine clever data structures for map[uint8]bool
that could involve storing the bools as bit fields. I wouldn't
implement that optimization now, but it seems like not a bad idea to
allow for future optimizations in the implementation.
David