FAQ

The solution sent a couple of days ago is eminently readable when the
reader is accustomed to Go idiom
I have to disagree entirely - it may be I'm using the word "semantics"
inappropriately here, but what I mean to say, is that append(list[:i],
list[i+1:]...) does *not* communicate intent. If anything, the word
"append" is misleading, since the resulting operation is the *opposite *of
appending: deleting.

My point is, when I'm reading through a function that happens to delete
something from a slice, I don't want to get distracted by misleading words
and lengthy expressions for something is trivial as removing an item from a
list.

Idioms or not, I don't understand how you can think that's a good thing.
Code should be legible. It should be express intent. It should not force
you to parse expressions or evaluate code for trivial operations.

Therefore, idioms or not, Caleb's example is useful, and I will be doing
exactly that - though it still feels rather strange to me, having to write
and maintain code for something as basic and common as this.
Another thing to consider is that deleting an item from the middle of a
slice is an expensive operation, resulting in potentially a lot of copying.
  Because of this, one can argue that this *shouldn't* be an easy thing to
do, to discourage its use when it's not appropriate

If you know that deletion from a slice is an expensive operation, that
should be discouragement enough - you really think it's reasonable to
punish people in situations where they do need to remove something from a
list?

I actually was discouraged when I saw the "idiomatic" way to delete from a
slice, and in this particular case, it directly influence the way this code
is organized, and in this case, made it more complicated than necessary,
and created some minor drawbacks.

My initial design had a boolean "once" flag on the Listener type, which
would indicate whether it gets dispatched once or many times. When I
realized how cumbersome it would be to remove items from the list, I
instead went for a design where Sink as two ListenerMaps - a dedicated one
for "once" listeners, and another one for "many" listeners.

Unfortunately, that design has a side effect: the order in which listeners
get notified is now inherently different from the order in which you
register listeners, because I have to now fire either the "once" or "many"
listeners first.

The other problem is that, even if this trade-off in functionality is
acceptable (and I don't know yet if it is) I still have to deal with the
problem of removal, since listeners can get un-registered, too. This
operation is now more complicated, since there are now two places to search
for a listener. And sure, I could denormalize the model some more, by
adding back the "once" flag to Listener, so I would know which map to look
in, but, am I still making things simpler, or am I making them more
complicated now?

I may be thinking or going about this all wrong, but it seems to me, in
this case, "less is more" isn't working for me, it's working against me -
it complicated the design, it made me accept a trade-off in functionality,
and it made me lose a lot of time on issues that are (or ought to be)
totally trivial.

Up until this point, I have come around and learned to like things that
seemed odd to me at first, but this one is... I don't know... how come
delete was deemed necessary for maps, but not for slices?

If you can think of a design approach that completely eliminates the need
to delete from slices, I'm all ears.

If not, well, I guess if I'm the only one who doesn't love reading these
lengthy expressions for trivial operations, well, I will go with Caleb's
approach, and I guess I'll be doing a lot of copying and pasting ;-)


On Wed, Mar 19, 2014 at 12:37 AM, Dan Kortschak wrote:

The solution sent a couple of days ago is eminently readable when the
reader is accustomed to Go idiom:

func (listeners ListenerMap) remove(listener Listener) {
if list, present := listeners[listener.event_type]; present {
for i, item := range list {
if item.id == listener.id {
listeners[listener.event_type] =
append(list[:i], list[i+1:]...)
break
}
}
}
}

Becoming accustomed takes time, but it comes.

On Tue, 2014-03-18 at 23:04 -0500, Rasmus Schultz wrote:
I don't want to debate this at length, but this really isn't semantic:

s2 := append(s1[:i], s1[i+1:]...)

Semantic would be a keyword or something else that actually expresses
deletion, e.g.:

delete s1[i];

I understand that's not how slices "work" in Go - because the slice itself
is a value, and not an "object"... but from this example, it seems that's
both good and bad - though most of the time thus far I have thought this
was a good thing, when you want to manipulate an existing value, even for a
simple manipulation like removing an item (or excluding it) this really
doesn't come out legible at all... "parsing" all those parens and brackets
and colons is *hard*...

Any chance Go will ever have something like e.g. macros or "inline"
functions, which could be used to give name (thus adding semantics) to
simple operations like these?

But back to the situation at hand -
you might consider using a custom slice type with methods to make it
look
nicer

I really would like that - could you give an example of doing that?

Thanks guys.
--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

Discussion Posts

Previous

Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 19 of 30 | next ›
Discussion Overview
groupgolang-nuts @
categoriesgo
postedMar 17, '14 at 3:34a
activeMar 20, '14 at 3:25a
posts30
users14
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase