Live data from Hacker News

Go at SoundCloud

backstage.soundcloud.com

101–110 of 112 posts

Re: Go at SoundCloud

#101
post #4

Earlier quoted context omitted.

It makes me think of getting rid of OOP and saying goodbye to the overengineering overhead it involves. It took us 25 years to begin to see that the king is naked! UPDATE: I have a feeling that in 25 years we'll be dissing the current fad du jour - functional programming.

But Go doesn't get rid of OOP, it just fixes it.

> But Go doesn't get rid of OOP, it just fixes it.

The only problem with OOP is people using OO without taking the time to learn it properly.

Re: Go at SoundCloud

#102
post #94

Earlier quoted context omitted.

How did you solve the problem in your matrix libraries of overloading a single operator multiple times? I was trying to make rudimentary, game-oriented linear algebra library in rust along the lines of glm. I immediately ran into the problem of not being able to implement "mat4 * float->mat4", "mat4 * vec4->vec4" and "mat4 * mat4->mat4" overloads at once. The alternative was only to go with "mult_float", "mult_vec4"…

I don't know rust but rust seems very much like C++. Did you have a look at the Eigen library (C++)? http://eigen.tuxfamily.org/dox/TutorialMatrixClass.html I have never worked with this library but it seems to me that they have not the problems you described. Maybe having a look at it brings up some new ideas...

Although on superficial level it shares the AGOL/C-style syntax, Rust is a very different language from C++. Some things are possible or easier in Rust as opposed to C++ and vice-versa. Copying directly from a C++ library would be difficult, and wouldn't take advantage of Rust's unique strengths.

Re: Go at SoundCloud

#103
post #6

We've just started using Go as well. It smokes our Python app in terms of speed, and is fun to use (maybe just because it's new?). I have always wondered, however, that if moving to a new language seems great because of the language, or because you have such a better understanding of the implementation of the problem you are trying to solve.

You bring up an interesting point about "new." New is fun. Exploration is fun. I think a lot of people will swear by a new language simply because it's not old and probably doesn't suffer many of the same deficiencies they're used to in their "every day," language. This to me is an illusion however. One must remain skeptical and treat new, untested languages with even more scrutiny than an old one. Many of these new…

New vs Better is also an interesting point. In this case, Go is a leap forward from Python in terms of language quality and predictability. It even provides you are proper concurrency framework - something all modern languages need.

Re: Go at SoundCloud

#104
post #102

Earlier quoted context omitted.

I don't know rust but rust seems very much like C++. Did you have a look at the Eigen library (C++)? http://eigen.tuxfamily.org/dox/TutorialMatrixClass.html I have never worked with this library but it seems to me that they have not the problems you described. Maybe having a look at it brings up some new ideas...

Although on superficial level it shares the AGOL/C-style syntax, Rust is a very different language from C++. Some things are possible or easier in Rust as opposed to C++ and vice-versa. Copying directly from a C++ library would be difficult, and wouldn't take advantage of Rust's unique strengths.

Okay. Thanks for the info. I just had a quick look at Rusts wikipedia entry and saw that it has been influenced by C++. But as you pointed out, this might not mean much...

Re: Go at SoundCloud

#105
post #38
post #25

Earlier quoted context omitted.

...Go still has objects. It's not the notion of binding functions to data that's flawed; it's classical inheritance that's flawed.

In my opinion, even the former notion is to a large extent flawed... Sure, there are several classes of different datatypes that really are different (e.g. mathematical objects, such as vectors, matrices, real numbers, ratios, complex numbers, ..., then strings, channels, binary data, time data...), but most data structures used in most programs are simply either sequences, or maps (dictionaries). I prefer Lisp's/Clo…

>I prefer Lisp's/Clojure's approach here - have many functions operating on few data types, as opposed to the inverse.

...that doesn't accurately describe a flaw in Go at all, and stems from a common misconception of Go's type system; namely that it is Java's type system, which it is decidedly not. The interfaces make a big difference.

An interface is simply a set of methods. Any object that implements those methods implements that interface. Adhering to an interface is implicit; you never have to say "type Stanley implements the Cat interface". If the Cat interface is just a "Meow" method, and Stanley can "Meow", Stanley is a Cat.

Take, for example, the io.Writer interface. io.Writer is a method set that contains a single method: the write method. This is the definition for io.Writer:

    type Writer interface {
        Write(p []byte) (n int, err error)
    }
This interface definition says "a Writer is any object that has a Write method. The Write method must accept a slice of bytes as its only argument, and it returns an integer and an error". Any object that implements this method also implements io.Writer. Therefore, any function that accepts an io.Writer may accept any object that defines this method. (when accepting io.Writer, the object's type is io.Writer; the only thing you can do with an io.Writer object inside of a method that accepts an io.Writer parameter is utilize its Write method, since that's the only thing you know it has).

So, for example, in the encoding/json package, there is an Encoder object. The Encoder object has just one method: the Encode method. This is the signature for the Encode method:

    func (enc *Encoder) Encode(v interface{}) error
this method definition reads "the function for the * Encoder type called Encode accepts an interface{} v and returns an error". interface{} is the empty interface; all objects implement at least zero methods, so any object can be supplied; it is valid to pass any object into the Encode method. The returned "error" value will let us know if something has gone wrong.

Now then. We know that we're encoding data to the json format, but to where is it being encoded? Where is the output going? The io.Encoder object embeds an io.Writer object; encoded items are written into the writer. That's a big leap. How do we know which io.Writer to write to? We inject the io.Writer when we create the encoder. This is the signature for the function that creates a json encoder:

    func NewEncoder(w io.Writer) *Encoder
It has only one argument; io.Writer. io.Writer has only one method; the Write method. That means that for any data target at all, if you define a Write method, you can encode json to it.

So what io.Writers are commonly found? There is an io.Writer for a UDP socket, a TCP socket, a websocket, an http response, a file on disk, a buffer of bytes, etc. The list goes on.

With this one Encode method, and this one Write interface, we are able to Encode json data to arbitrary targets. There's none of that JSONFileWriter, JSONHTTPResponseWriter, JSONUDPSocketStreamer stuff like you would get in other statically typed languages.

Re: Go at SoundCloud

#106
post #94

Earlier quoted context omitted.

I wish I could agree, but experience has shown that not having operator overloading makes (a) operating polymorphically over different number types and (b) creating new number types (decimals, bigints, etc.) really awkward. The former is much of the reason we had to add it to Rust. We have matrices that can operate over any numeric type T that implements the basic operations (so we can write matrix math once and have…

How did you solve the problem in your matrix libraries of overloading a single operator multiple times? I was trying to make rudimentary, game-oriented linear algebra library in rust along the lines of glm. I immediately ran into the problem of not being able to implement "mat4 * float->mat4", "mat4 * vec4->vec4" and "mat4 * mat4->mat4" overloads at once. The alternative was only to go with "mult_float", "mult_vec4"…

I was about to say "you can't do it", but I think you can -- the trick is to use a bounded generic implementation. Once "Mul" becomes a trait, you'll be able to say this:

    trait MatrixMultiplyRHS {
        fn mul(matrix: Matrix) -> Result;
    }

    impl,Result> Matrix : Mul {
        fn mul(rhs: RHS) -> Result {
            rhs.mul(self)
        }
    }

    impl float : MatrixMultiplyRHS {
        fn mul(matrix: Matrix) -> Matrix {
            // ...implementation of matrix scalar multiply...
        }
    }

    impl Vector : MatrixMultiplyRHS {
        fn mul(matrix: Matrix) -> Vector {
            // ... implementation of matrix multiply for vectors ...
        }
    }

    impl Matrix : MatrixMultiplyRHS {
        fn mul(matrix: Matrix) -> Matrix {
            // ... implementation of matrix multiply for matrices ...
        }
    }
It's admittedly a bit awkward, but maybe that's OK to discourage overloading unless you actually need it. Still, your point was very interesting -- I didn't realize this was possible! -- and I'll spread it around the team.

Re: Go at SoundCloud

#107
post #94

Earlier quoted context omitted.

How did you solve the problem in your matrix libraries of overloading a single operator multiple times? I was trying to make rudimentary, game-oriented linear algebra library in rust along the lines of glm. I immediately ran into the problem of not being able to implement "mat4 * float->mat4", "mat4 * vec4->vec4" and "mat4 * mat4->mat4" overloads at once. The alternative was only to go with "mult_float", "mult_vec4"…

I was about to say "you can't do it", but I think you can -- the trick is to use a bounded generic implementation. Once "Mul" becomes a trait, you'll be able to say this: trait MatrixMultiplyRHS { fn mul(matrix: Matrix) -> Result; } impl ,Result> Matrix : Mul { fn mul(rhs: RHS) -> Result { rhs.mul(self) } } impl float : MatrixMultiplyRHS { fn mul(matrix: Matrix) -> Matrix { // ...implementation of matrix scalar multi…

Ahh neat.

Just as a warning, I've already aired this topic on github, so maybe that might be a good place to discuss it: https://github.com/mozilla/rust/issues/2961

I don't want to cause a fuss. While Rust might not work for my needs/wants/desires, that's ok. I highly respect those who don't attempt to please everyone. :)

Re: Go at SoundCloud

#108
post #26

Earlier quoted context omitted.

Go doesn't "lack error-handling." They're referring to the fact that Go doesn't have exceptions; you check return codes to detect and handle errors. For some this is tedious, but has advantages (mentioned in the article) with respect to understanding an entire program.

The problem is it's no better than C - the correct way is to return sum types, either values or errors. A good language would statically check that any returned values are only used when there are no errors, preventing invalid values being accessed. This requires some flow analysis, but brings real benefit and safety.

yeah, sum types are my #1 missing feature in go. i'm excited that mozilla's rust has decided to add them.

Re: Go at SoundCloud

#109

Earlier quoted context omitted.

You're jumping to a false conclusion that Go's designers were not aware of those language features, and that that was the reason why they aren't in Go.

Care to give an alternative explanation to the contents at the other side of the URL I gave?

You said that sum types were omitted from Go because the designers were not aware of more recent developments. That's not true. They were omitted because they do not mesh well with the other features of the language, such as zero types, interfaces and embedding.

Whether you agree with that latter point is moot. Go's designers were and are fully aware of sum types; they chose to omit them from Go for a reason, not because they were ignorant of their existence.

Re: Go at SoundCloud

#110
post #65

Earlier quoted context omitted.

And how do you know what add(foo, bar) does internally?

add(foo, bar) isn't any clearer than foo + bar, but usually an overloaded operator doesn't correspond to "add". For example, in Javascript: "Hello" + " " + "World!". What the operator there is doing is concatenating the strings, so if you had a method to do it you wouldn't call it add - you'd call it concat.

> For example, in Javascript: "Hello" + " " + "World!". What the operator there is doing is concatenating the strings

Hmm, are we talking about (user defined) operator overloading as a language feature, or about overloaded operators? For example, I hate that 1/2 and 1.0/2 are different things in most languages, but I haven't heard anyone call this operator overloading in the context of C.

Post reply on HN