Live data from Hacker News

Everyday hassles in Go

crufter.com

261–270 of 297 posts

Re: Everyday hassles in Go

#261

Earlier quoted context omitted.

If we assume the operations we're talking about take time linear in proportion to the list, you've just gone from a * n time to b * n time, where b > a. Both of these are still O(n) in Big O notation, which drops constants, because constants unless they're very large or n is extremely large, tend to have relatively little effect on the running time of an algorithm. Choosing to write more verbose, difficult to deciphe…

My comment was carefully worded in order to denote that it is not true in all cases. Your Big O analysis is correct. However, in a real-world case the list could be an iterator over a log file on disk. Then you really don't want to use chained combinators, repeatedly returning to the disk and iterating over gigabytes of data on a spinning plate. And yeah, you could benchmark to figure that out, or you could use the r…

Or you could use a library explicitly designed with these considerations in mind, that offers the same powerful, familiar combinators, with resource safety and speed. e.g.,

Machines in Haskell: https://hackage.haskell.org/package/machines

Scalaz Stream in Scala: https://github.com/scalaz/scalaz-stream

I've no doubt an equivalent exists for Clojure, too, although I'm not familiar enough with the language to point you in the right direction.

One of the most amazing things about writing the IO parts of your program using libraries like these is how easy they become to test. You don't have to do any dependency injection nonsense, as your combinators work the same regardless of whether they're actually connected to a network socket, a file, or whether they're just consuming a data structure you've constructed in your program. So writing unit tests is basically the same as testing any pure function - you just feed a fixture in and test that what comes out is what you expect.

I found this really useful when writing a football goal push notifications service for a newspaper I work for. I realised that what the service was essentially doing was consuming an event stream from one service, converting it into a different kind of stream, and then sinking it into our service that actually sent the notification to APNS & Google. The program and its tests ended up being much more succinct than what I would normally write, and the whole thing was fun, and took hardly any time.

I would say that is the right tool for the job.

Re: Everyday hassles in Go

#263

Earlier quoted context omitted.

> I am looking for a replacement programming language to solve small problems for which Python/Ruby would have traditionally been used, good file system, stream and networking APIs, but concurrency as a first class citizen, garbage collected, fast startup time. You just described Go, mostly. I can't think of a more fitting language given your stated requirements. To your first point: I don't know what Go has to do wi…

Yes, I did describe what Go is good at, that's because I am trying to find something to put it against for what I use it for currently. Let's say I prefer Haskell's syntax/approach. Coming from Go, what could I be missing in Haskell?

The ability to easily solve problems Go was made to solve (mainly, server programs and OS utilities). Those problems are, often, inherently easier to express with an imperative style (because they deal a lot with the external, imperative world and all its nasty aspects).

You might also loose the ability to know how much memory and time a given task requires at most, which can be a problem when dealing with servers (it's much harder to know how many requests you will be able to serve per second or how long a given request will take to be treated, for instance).

Re: Everyday hassles in Go

#264
post #245

Earlier quoted context omitted.

Did you ever work with a list? Did you ever do things like foo = [bar(x) for x in quux] Or did you ever flatten a nested list? Congratulations, you've been using one of the most widespread monads. Monads are not artificial constructs. Monads, like functions, or loops, or conditional statements, emerge naturally when you try to describe a computation, even a simple one. This is like speaking prose without knowing that…

No, actually, I don't do things like that (see my parallel reply to codygman). The Haskell types often seem to think that the computing they do is the same as the computing that everybody else does, and therefore that the problems that they want to solve are the ones that everybody else wants to solve. That's not a very accurate assumption.

Just for reference: what are the kinds of problems you solve?

Note that the code I quoted above is Python, and I have lots of stuff like that in my mundane production code (processing files, tracking transactions, counting money, etc).

Re: Everyday hassles in Go

#265
post #247

Earlier quoted context omitted.

What makes you think it can't be measured? Just because we don't have the infrastructure to do it doesn't mean it can't be done. >The reason people keep saying that we don't have any measures that do this, is that it is a bafflingly tricky problem that has been studied for decades with hardly any forward progress And what if I had a solution? How does this comment help anything? What do you think the difference is be…

>I don't know why people keep saying this. What I'm getting at is that determining which of 2 pieces of code are better is one of the biggest open question in the computer science/software industry. Further, it has been widely studied for a long time and across a wide variety of measurements and contexts, yet remains an open question. If you have a measure that can be systematically reproduced by anyone for any 2 pie…

This is a very complex problem on a very volatile dataset. It would be like asking a physicist to predict the outcome of an foot race by calculating a complete quantum description of all the runners.

If that is your standard, then it is highly impractical, but not theoretically meaningless. However, "determining which of 2 pieces of code are better" is not such a problem. It is one that can be solved by heuristics and approximation, just the same as predicting the outcome of a race can.

So while there is as of yet no perfect algorithm, I would strongly disagree that there is _no_ algorithm or that there is no way to compare different algorithms meaningfully. We have measurements, and just because they are not perfect doesn't mean they cannot be verifiably correct within a useful margin of error.

We can reliably tell which two pieces of code are better. We cannot do it with extreme precision, and we cannot do it quickly enough to make predictions, but this does not mean that the concept of 'better code' is invalid or not understood in a productive sense. It certainly doesn't mean you can't make informal arguments from it.

Re: Everyday hassles in Go

#266
post #178

Earlier quoted context omitted.

Are generics really that important? Java didn't have generics for 9 or 10 years, C# only got them in version 2. C still doesn't have generics and I never heard anyone complain. As a former C# developer I would agree that life got easier with the introduction of generics, but you can develop the exact same software with and without generics.

> C still doesn't have generics and I never heard anyone complain. People who would complain already know not to bother using C.

To be more fair, I'd say people using C are not people solving abstract problems that can profit from a generic approach.

Re: Everyday hassles in Go

#267

The article author points out, correctly, that Go code has far too much "interface{}" in it. That's an indication of real need for more power in the type system. Generics may be overkill. Parameterized types may be enough. The difference is that you have to explicitly instantiate a parameterized type. Generic functions and classes get instantiated implicitly when used, which gets complicated. (See C++'s Boost.) Go al…

That's not really the full story though. The parameterized type isn't just `map[K]V`, it's more than that. The type `K` needs to be hashable, and not all types support that. e.g., slices do not: http://play.golang.org/p/IKp_I25NW2 It gets more complicated then that too, because composite types can be used for keys, but only if the type does not contain any non-hashable type.

Similarly, if you're going to build a binary tree data structure, then you probably need a way to compare elements. How do you express that constraint?

Standard ML has a similar limitation, which resulted in the presence of an `eqtype`, which is basically a way of saying, "any type T that can be compared for equality." But of course, ML has its modules...

So I'd argue that type parameterization alone doesn't really buy you much. You might say: well, we need bounded polymorphism then. OK. How do you define bounds? Maybe you figure out a way to abuse interfaces (but a bound isn't a type while an interface is a type), or you add a new way of specifying interfaces to the language.

The road to generics is long, complex and fraught with trade offs. Blessing a few key parametric types is a really interesting compromise, and I believe it's one that was absent in a similar practical manner in pre-generics Java and C++.

Re: Everyday hassles in Go

#268

Earlier quoted context omitted.

The purity is not an illusion though. Writing those sequences as a monad gives you the ability to compose actions, creating a new sequence from code you've already written for one.

But that's not a net win for me, compared to just having the action in a function that is called from several places. Worse, composing the actions means I have to think through how the composing is going to affect the sequencing of events. Just having a function doesn't give me that problem - the sequencing is explicit, not hidden, and therefore is easier to reason about.

Can you give me some example code? I think our discussion would be a lot more productive and mutually beneficial with some code examples/output.

Re: Everyday hassles in Go

#269
post #143

Earlier quoted context omitted.

While I understand your comment, I have to disagree. Programming languages should be kind of boring, and support the average developers' work. That is why Haskell will ultimate fail and fade away - most of the developers on this planet are simply not skilled enough to touch any of that stuff. Attempting to add all Ninja concepts to a language will just lead to a massive failure. Go does a very good job on forcing eve…

First of all, you're making the enterprise java argument. Which is valid, but drives me to suicide. Furthermore ... Go ... succinct ... elegant ... using reflection as an alternative to generics ... In my experience Go is neither succing (if err { ... } one-statement if err { ... } one-statement if err { ... } one-statement). It is extremely inelegant because due to the confused sequence of statements it isn't possib…

Go's philosophy is to consider errors and failures are part of solving problems, not something "exceptional" that should make you fail and refer to a higher authority. Error-checking and error-reporting is not something that is distracting the normal flow of your function : it is part of the normal flow of your function.

Re: Everyday hassles in Go

#270
post #245

Earlier quoted context omitted.

Did you ever work with a list? Did you ever do things like foo = [bar(x) for x in quux] Or did you ever flatten a nested list? Congratulations, you've been using one of the most widespread monads. Monads are not artificial constructs. Monads, like functions, or loops, or conditional statements, emerge naturally when you try to describe a computation, even a simple one. This is like speaking prose without knowing that…

No, actually, I don't do things like that (see my parallel reply to codygman). The Haskell types often seem to think that the computing they do is the same as the computing that everybody else does, and therefore that the problems that they want to solve are the ones that everybody else wants to solve. That's not a very accurate assumption.

> The Haskell types often seem to think that the computing they do is the same as the computing that everybody else does

Seeing as Haskell is used for general computing (including embedded software) the computing is the same. I know what you ate getting at, but I don't think it is based on facts or anything rational.

Post reply on HN