Hacker News new | ask | show | jobs
by hknmtt 999 days ago
I am a Go fan and have been coding in it for years, but this crap:

func Clone[S ~[]E, E any](s S) S { return append(s[:0:0], s...) }

looks just like Rust, which has the fugliest syntax I have ever seen. Personally I use maybe 3 or 4 generic functions to work with arrays(oh, sorry SLICES), otherwise I do not touch them. Could not care less about them and all that noise they caused.

2 comments

In go, the stdlib impl is actually:

    func Clone[S ~[]E, E any](s S) S {
      if s == nil {
        return nil
      }
      return append(S([]E{}), s...)
    }
    
For comparison, `vec.clone()` in the rust stdlib is:

    pub trait Clone: Sized {
      fn clone(&self) -> Self;
    }

    impl<T: Clone> Clone for Vec<T> {
      fn clone(&self) -> Self {
        <[T]>::to_vec(&**self)
      }
    }
I think the rust one is much easier to read. The go one has an if statement, which means the go one has higher cyclomatic complexity, and is thus harder to understand and reason about.

The rust one does have "&**self", which looks a little strange perhaps, but overall seems simpler than the go one.

What is “&**self” called?
It is so simple it does not have a name. It is simply a double deref + borrow.

Since "deref" can be implemented differently for each type, you cannot know what it does in general, but in this case '*Vec<T>' turns it into a '[T]'.

If you compile in release mode, all of the following implementations of 'clone' will emit identical assembly:

    <[T]>::to_vec(&**self)

    <[T]>::to_vec(&self[..])

    <[T]>::to_vec(self.as_slice())

    self.as_slice().to_vec()
The stdlib picked the coolest looking one. Can't fault them for that.
Honestly I'd have preferred `.as_slice().to_vec()`
It reborrows `*self` als a slice. I prefer The Methode `as_slice` which does the same.
Yeah, that one if statement really melts my brain. /s
I'm okay with code like this being tucked away in the std lib (or a 3rd party library) IF it makes my own code easier, and in this case it does since calling it is just

    c := Clone(ms)
(which is highlighted in the article)