News for hackers. Stuff that matters.
Re:Go makes it easier to write correct, clear and efficient ... by siscia on Friday May 10, 2019 @04:19AM (#19876045)
I do like go, but really this arguments start to be a little unprofessional if you ask me.

All those arguments are fine and correct in small projects or libraries, there go is perfect.

But they really don't hold on big project like docker or containerd.

While it is clear what lines of code does, at a tactical level, it is extremely difficult to follow what happen in the big picture, the strategic level. Where the values comes from and where they go? When? How and why?

Honestly I keep seeing this in all big go project, despite the lack of generics.

Again if you need a small micorservice, use go! It is the best option right now. But I wouldn't bet any big codebase on it.

Re:Go makes it easier to write correct, clear and efficient ... by kenhwang on Friday May 10, 2019 @04:22AM (#19876053)
I think complexity in software becomes difficult to grok as software gets bigger, and go does seem to go out of their way to code easier to understand at a hilariously micro scale at a huge cost at the macro level.
Re:Go makes it easier to write correct, clear and efficient ... by sagichmal on Friday May 10, 2019 @04:46AM (#19876148)
Absolutely the opposite. The ability to understand Go code seems roughly constant with regards to codebase size.

On teams of enough engineers, especially as those engineers rotate in and out of maintenance roles, richer abstractions tend to obfuscate intent and hurt maintainability more than help it.

Re:Go makes it easier to write correct, clear and efficient ... by asdkhadsj on Friday May 10, 2019 @08:27AM (#19877048)
Having been a professional Go programmer for ~5 years prior, now working in Rust full time, I actually take issue with Go for large code bases[1].

For me it's mainly due to the lack of generics and helper tools that naturally spawn from generics. Go's solution to having less LOC inside a function is _only_ to create helper methods/funcs. These helpers are bound to specific data structures and often are only applicable to that one use case in that one method that they came from. Your ability to make that helper function apply to more code depends heavily on what data structures are being used.

This form of non-generic bloat was far worse for me than the classic examples of `Fooi32()` and `FooString()`. The latter I don't mind at all.

Rust aids this process to me by, well, having generics. Converting one data structure into another becomes a breeze, and converting a Slice of those data structures is just as easy. I'll be really interested to see how Go feels once generics make it in - though I suspect I'll stick with more explicit memory management.

Speaking of memory management, it would be nice if Go had a way to intelligently indicate which structures are safe for concurrent use and which aren't. I've found in Rust that the explicit nature of the concurrent safety is not something I knew I wanted in Go. I know Go will not likely ever match Rust's safety, but if it at least indicated that something was an thread-unsafe implementation that would be golden.

[1] edit: Oh, and there is a disclaimer in this that the projects I'm involved in seem to heavily rely on managing several data structures in repeated ways. Aka, very generic friendly.. so not having generics made my projects extra painful. This is not likely the norm.

Re:Go makes it easier to write correct, clear and efficient ... by apta on Friday May 10, 2019 @10:32AM (#19878085)
> actually take issue with Go for large code bases

This has been my experience as well. People just parrot what the golang authors say about it being a language suites for "large scale development", whatever that means, without providing anything to back it up. Just because they said it was must be it's true? In practical experience, it's a verbose, clunky, and awkward language to use for any non-trivial code bases.

Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @10:37AM (#19878140)
Your disclaimer isn't really needed. Good generics support leads to good standard libraries, and using standard libraries is the norm.

Rust is still too young to take advantage of this, but in due time it will.

Re:Go makes it easier to write correct, clear and efficient ... by asdkhadsj on Friday May 10, 2019 @04:48PM (#19882085)
> Rust is still too young to take advantage of this, but in due time it will.

I actually find Rust's standard library great. I think my only complaint so far is the lack of time handling. Luckily community packages (like Chrono, Diesel, Tokio, Hyper, Itertools) have implemented great solutions to a few missing details.

Hell, Iterators alone make my life so much better.

Re:Go makes it easier to write correct, clear and efficient ... by snovv_crash on Friday May 10, 2019 @12:21PM (#19879266)
Go is designed to do concurrency via message passing, not shared memory. Yes, this is slower, but it also means you don't need a fancy borrow checker slowing down your compile.
Re:Go makes it easier to write correct, clear and efficient ... by nazka on Friday May 10, 2019 @12:58PM (#19879730)
Let me rephrase. Go was designed with the old best practice to share data of languages before Rust came: “you do not communicate by sharing memory, instead you share memory by communicating”. It is slower but you have to do this because Go can’t guaranty memory safety and doesn’t have system to prove that at compile time.

Then the team behind Rust after many research found that you can actually guaranty memory safety if you can track how data are used by each thread. To do this you need to track how each value is used and borrowed by each thread to insure memory safety. And so the borrow checker was born. It gives you the best of both world: speed And safety while adding only a little bit of time to the program to compile.

If Rust is slow to compile it’s not because of the borrow checker it only adds a little bit to the bottom line, but it’s because of Generics and other things. Which is also something that Go is lacking and doesn’t have yet.

Re:Go makes it easier to write correct, clear and efficient ... by perfmode on Friday May 10, 2019 @12:42PM (#19879528)
instead you pay for context switches in the scheduler and suffer an order of magnitude slowdown in production. and when you profile and find the performance issue, you rewrite the portion of code to use mutexed shared memory to hit your performance targets.
Re:Go makes it easier to write correct, clear and efficient ... by piano on Wednesday May 15, 2019 @09:56AM (#19919385)
> Go is designed to do concurrency via message passing, not shared memory.

... and yet experienced gophers will criticize newcomer's code for using channels too much and they will tell you you need to use traditional stupid shared memory approach instead of channels in many cases.

Re:Go makes it easier to write correct, clear and efficient ... by PeterisP on Friday May 10, 2019 @06:15AM (#19876482)
For complex, specialized systems what I'm often seeing is that essentially every decent large system gets split into a de-facto domain specific language (no matter if it's with language features or through some specialized libraries or webservices or whatever API) and the implementation of the business logic in that DSL. And, in general, the implementation of that DSL is something like ten times smaller than the amount of code using that DSL.

The maintainability of the code is mostly determined not by how good the underlying language is but how good is that DSL. To take an example that's been widely discussed in HN, let's think about machine learning - the look, structure and maintainability of your code is highly influenced by the choice of your framework/"DSL" e.g. pytorch vs tensorflow1.x vs straight numpy vs Caffe will have major differences despite being in the "same language".

And in that regard, the features of the core language matter only in regard of whether they facilitate making a good DSL. Of course, some languages fail because their choices result in the "core DSL" i.e. standard libraries that everybody uses being fragmented and confusing; Go has it quite good IMHO for the standard library; but for every specific domain it also matters if the DSL for that domain is good, whether it's an ORM layer or a OpenGL interface or a deep learning framework or an physics simulation library - whether the language abstractions mean that these DSL's (often being interfaces/wrappers to some third-party code written in another language) are going to be good and convenient, or whether the language structures limit the DSL so it becomes unwieldy to use.

Re:Go makes it easier to write correct, clear and efficient ... by sagichmal on Friday May 10, 2019 @07:17AM (#19876731)
> For complex, specialized systems what I'm often seeing is that essentially every decent large system gets split into a de-facto domain specific language

Every time I've seen this, it's been a disaster. Custom DSLs for business logic are, 100% of the time, a red flag of a development process gone off the rails.

(We may work in different industries.)

Go prevents you from doing this at a very low level. This is a huge advantage.

Re:Go makes it easier to write correct, clear and efficient ... by PeterisP on Friday May 10, 2019 @07:49AM (#19876863)
If you're writing a React or Django or Laravel or Rails app, then what you're doing is essentially work within that DSL which is quite different from the underlying Javascript/Python/PHP/Ruby language. The same goes for data analysis frameworks such as Pandas, or deep learning such as Tensorflow or Keras - if you're working in that most of your code and calls are going to be within that API/DSL, not "pure" Python. And I'd definitely consider all of the abovementioned as successes and a good thing - if Go would prevent people from writing their Web-CMS systems in a good Web-CMS framework/DSL, or writing their machine learning systems in a good ML framework/DSL, then that'd be a serious limitation.

And it's worth noting that many (all?) of these particular systems were actually initially made as custom DSLs for internal use within a single company - Rails for 37signals/Basecamp, Pandas for AQR Capital Management, Django for Lawrence Journal-World, Tensorflow by Google Brain, etc. They were the exact thing that you describe - a custom DSL invented for the business logic that the particular company needed repeatedly. And they were not a disaster but the right thing to do in their case - mostly because they had the ability to make a somewhat good DSL though in all those cases it was an 'okayish' DSL initially and became good only through years of substantial changes. Yes, for every such case there are many bad internal DSLs. "Not Invented Here" is a common problem. You need to ensure that you're using good DSLs, and good DSLs generally gain wide adoption within that domain instead of every company building their own shoddy DSL.

I've seen a bunch of nightmarish financial systems with horrible DSLs. However, even in that case the DSL problem was that this DSL was horrible not that a DSL shouldn't have been used - any fix or rewrite would generally require replacing it with a better DSL/framework/whole-encompassing-structural-API/whatever, instead of sticking to the core programming language (which would just result in another emergent "DSL" of some core libraries/classes, which would be lousy compared to something you intentionally design to be usable).

Re:Go makes it easier to write correct, clear and efficient ... by orbifold on Friday May 10, 2019 @11:51AM (#19878920)
I would say most of the examples you mentioned are actually examples of well implemented libraries, with well named methods and abstractions, rather than DSLs. If you want to imply that a good large codebase is similarly structured into libraries of independent components rather than one big class hierarchy then I would agree.
Re:Go makes it easier to write correct, clear and efficient ... by PeterisP on Friday May 10, 2019 @12:07PM (#19879109)
I'm probably trying to make a point that when writing code to a large domain-specific library or framework, at a certain level of intensity of coupling it de facto becomes a DSL. You're writing code using "primitive" data types, data structures and functions specific to that DSL instead of the data types of your core language; the control flow and data flow is not the same as in your core language but determined by that framework.

The differences between programming languages are smaller than the differences between DLS's implemented in the same language. Code in Rails (Ruby) and Django (Python) has more in common than code for Django and Pandas. Writing Tensorflow code in Python is somewhat similar to writing TensorflowJS code in Javascript, but very dissimilar to writing Pytorch code that does the same thing.

They're not really independent libraries, they're frameworks that suggest, influence and sometimes even mandate most of the infrastructure around your code and the structure of your code in a much more stringent manner than the core language does. There's a fundamental difference between making a few calls to a black box library versus having the content and style of most of your code being dominated by the traits of that "library" - the large frameworks overwhelm the small(ish) core languages. So I believe it's justifiable to consider the frameworks I mentioned as DSLs.

Re:Go makes it easier to write correct, clear and efficient ... by jimbokun on Friday May 10, 2019 @11:54AM (#19878954)
As PeterisP mentions, TensorFlow is an example of a massively, unequivocally successful DSL, which really wouldn't be possible with Go.
Re:Go makes it easier to write correct, clear and efficient ... by notacoward on Friday May 10, 2019 @09:43AM (#19877586)
Replace "DSL" with "idiom" and I totally agree with you. It's often possible to look at a code snippet and recognize what codebase it's from, even if it's doing something pretty generic. There are explicit local APIs, implicit local APIs (often associated with local data structures or stores), and local habits such as looping over items in a particular way. Managing memory, scheduling work, logging, and so on all tend to follow local rules. Those rules together are the moral equivalent of a DSL.

So you're right, for programming in the large it's very important how well the language supports creating good reusable APIs and data structures. I think that's why so many people make such a big deal about generics in Go, though personally I think it's a poor example and the complaints are tiresome. I think I'd focus more on whether the language has things like macros and lambdas/continuations that let non-API idioms be expressed consistently and conveniently, as though they're part of the language (even though I think creating a true DSL is usually a bad idea). Not sure Go meets this standard TBH.

Re:Go makes it easier to write correct, clear and efficient ... by jcadam on Friday May 10, 2019 @07:23AM (#19876757)
> ...the features of the core language matter only in regard of whether they facilitate making a good DSL.

Well, nothing I'm aware of beats the LISP family of languages as far as "making a good DSL" goes, but none of those are particularly popular :(

Re:Go makes it easier to write correct, clear and efficient ... by bsaul on Friday May 10, 2019 @07:56AM (#19876893)
except lisp aren’t statically typed, and so provide no refactoring capability or minimal safety at compile time.

But that’s another topic.

Re:Go makes it easier to write correct, clear and efficient ... by lispm on Friday May 10, 2019 @08:41AM (#19877155)
CLOS code:

   (defclass foo (superfoo1 superfoo2)
      ((some-slot :type bar)))

   (defmethod baz ((some-foo foo) (some-bar bar))
     ...)

   (defmethod foobar ((some-foo foo))
     (baz foo (make-bar)))
What would you need to do refactoring operations on such code? Given that there are classes, arguments are specialized over classes, slots have types, ...
Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @10:40AM (#19878180)
> What would you need to do refactoring operations on such code?

Some tool that can point where in a 1M lines of code project those classes are being used, and if they would need to change.

Re:Go makes it easier to write correct, clear and efficient ... by lispm on Friday May 10, 2019 @10:44AM (#19878222)
sure, go ahead. The type information is there.
Re:Go makes it easier to write correct, clear and efficient ... by bsaul on Friday May 10, 2019 @12:28PM (#19879335)
Didn't know about those type annotations in lisp, but i suppose what you mean is that an ide could parse all the code, infer the type of all the function / variables etc (just like the lisp interpreter would) and provide you with refactoring facilities ?

That's a good thing. But then comes the git merge (or any other automatic code altering tool). How do you know something hasn't been messed up in the process ? (unless you wrote unit test for every argument of every function)

Re:Go makes it easier to write correct, clear and efficient ... by lispm on Friday May 10, 2019 @12:50PM (#19879632)
> lisp interpreter

Lisp has compilers.

Some do also some type checking, here SBCL 1.5.2:

  (declaim (ftype (function (fixnum) fixnum) foo))
  (defun foo (a)
    (+ a 1))

  (declaim (ftype (function (fixnum) string) bar))
  (defun bar (a)
    (if (zerop a)
        "zero"
        "not-zero"))

  (defun baz (a)
    (foo (bar a)))
Then:

  * (compile-file "/tmp/test.lisp")
  ; in: DEFUN BAZ                                                                                                                                                                      
  ;     (FOO (BAR A))                                                                                                                                                                  
  ;                                                                                                                                                                                    
  ; note: deleting unreachable code                                                                                                                                                    
  ;                                                                                                                                                                                    
  ; caught WARNING:                                                                                                                                                                    
  ;   Derived type of (BAR A) is                                                                                                                                                       
  ;     (VALUES STRING &REST T),                                                                                                                                                       
  ;   conflicting with its asserted type                                                                                                                                               
  ;     FIXNUM.
Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @12:17PM (#19879214)
Indeed.

I had convinced myself I was reading Clisp, instead of CLOS.

Re:Go makes it easier to write correct, clear and efficient ... by lispm on Friday May 10, 2019 @12:40PM (#19879503)
CLOS is a part of Common Lisp. Fully integrated.
Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @12:42PM (#19879525)
Those type annotations are on clisp? I probably should get a project to test them :)
Re:Go makes it easier to write correct, clear and efficient ... by lispm on Friday May 10, 2019 @12:56PM (#19879700)
CLISP is an implementation of Common Lisp. The language is called Common Lisp.

Common Lisp has an object system with classes since the early 90s. In fact it was the first standardized object-oriented language.

Common Lisp also has optional type declarations. Not very sophisticated, but they are there.

Check out the SBCL implementation, which has a compiler which does some static type checking/inferencing.

http://www.sbcl.org

But one usually can use types/classes at runtime, too.

Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @02:17PM (#19880633)
Bookmarked for my next project. Thanks.
Re:Go makes it easier to write correct, clear and efficient ... by stouset on Friday May 10, 2019 @05:37AM (#19876335)
I just don’t buy it. We already work at a layer dozens if not more abstractions away from what’s really happening underneath the surface. This is essentially an argument that every layer below is good and justified, but that any additional layer is just too much.
Re:Go makes it easier to write correct, clear and efficient ... by coldtea on Friday May 10, 2019 @08:56AM (#19877252)
>Absolutely the opposite. The ability to understand Go code seems roughly constant with regards to codebase size.

That's what some Go proponents say, not necessarily reality, and there's no study about this, just hearsay.

I find Go hurts readability for larger programs because it prevents many structural abstractions that make code more clear and concise (as opposed to mere fancy "clever" code, which it still allows), and because it forces too much boilerplace (error handling, no generics, etc).

Every large projects contains re-implementations of the same things (from data structures to algorithms, to parallel processing handling) that could have been done once and re-used forever with generics and a little more power.

Re:Go makes it easier to write correct, clear and efficient ... by pjmlp on Friday May 10, 2019 @09:31AM (#19877490)
And then there is the copy-paste as means to avoid additional package dependencies.
Re:Go makes it easier to write correct, clear and efficient ... by r-u-serious on Friday May 10, 2019 @04:30AM (#19876090)
> Honestly I keep seeing this in all big go project, despite the lack of generics.

Not maybe because of the lack of generics?

Re:Go makes it easier to write correct, clear and efficient ... by siscia on Friday May 10, 2019 @04:44AM (#19876138)
I am not sure myself.

If I recall correctly one of the arguments for lack of generic was that they would make more obvious code, hence easier to follow and read. Actually it seems like the lack of generic just make more obvious code, hence more difficult to read.

The other argument was compilation speed, that honestly I cannot complain about.

Re:Go makes it easier to write correct, clear and efficient ... by jeremyjh on Friday May 10, 2019 @06:49AM (#19876629)
> If I recall correctly one of the arguments for lack of generic was that they would make more obvious code

I don't believe that is a reason ever articulated by the core team, but a post-hoc justification by apologists. The reason the core team gave was that they had not settled on a design that would fit well with their other goals for the language, and it simply didn't make the short list for 1.0.

Re:Go makes it easier to write correct, clear and efficient ... by fnord123 on Friday May 10, 2019 @04:40AM (#19876128)
>While it is clear what lines of code does, at a tactical level, it is extremely difficult to follow what happen in the big picture, the strategic level. Where the values comes from and where they go?

Compared to python or Java? Well written python basically resembles Go. And most Java I've come across tries to spread logic across class boundaries so you never get to have all the code in front of you at one time.

Re:Go makes it easier to write correct, clear and efficient ... by jeremyjh on Friday May 10, 2019 @06:56AM (#19876647)
Definitely Java has a very similar problem, of having so much rote boilerplate in every single class that its hard to see essential deviations from the pattern that you need to understand in order to follow the code. I have not ever seen this problem in a Python code base. It is not littered with "if err != nil" for one thing, but Java has exceptions too and still has this problem.

I attribute it more to a static type system that lacks features I've grown use to in modern languages. Most of my experience in Java is 1.6 and prior so its possible code bases have improved since then.

Re:Go makes it easier to write correct, clear and efficient ... by 0xdeadbeefbabe on Friday May 10, 2019 @11:44AM (#19878832)
Oooh I like the prospect of check(errProducingFunc()) https://github.com/golang/proposal/blob/master/design/go2dra...
Re:Go makes it easier to write correct, clear and efficient ... by deepsun on Friday May 10, 2019 @09:52AM (#19877672)
And Kotlin nowadays looks very much like Python, but it's same Java, just with syntactic sugar.
Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @11:52AM (#19878936)
KotlinLooksLikePythonWouldLookIfJavaDevelopersNamedThings
Re:Go makes it easier to write correct, clear and efficient ... by cbolton on Friday May 10, 2019 @06:24AM (#19876522)
Where the values comes from and where they go? When? How and why?

Could you give a couple of examples how this is made clearer in other languages?

Re:Go makes it easier to write correct, clear and efficient ... by deepsun on Friday May 10, 2019 @09:49AM (#19877655)
Not the author, but for Java IntelliJ has nice call navigation with tabs "dataflow to here" and "dataflow from here".
Re:Go makes it easier to write correct, clear and efficient ... by codr7 on Friday May 10, 2019 @04:41AM (#19876131)
And yet, people are building big code bases on top of both C and Go without generics all the time. Like C, Go lacks support for elaborate abstractions. It's still a better C for many problems.
Re:Go makes it easier to write correct, clear and efficient ... by giornogiovanna on Friday May 10, 2019 @05:20AM (#19876272)
People have probably reinvented generics thousands of times in C, mostly using function pointers or macro hacks.

Edit: And the intrusive data structures commonly used in C are way more complicated than the equivalent generic code (in my opinion).

https://lwn.net/Articles/184495/

Re:Go makes it easier to write correct, clear and efficient ... by wahern on Friday May 10, 2019 @12:22PM (#19879276)
The Linux kernel is the last place anybody should go to find simple, clean interfaces. That's just not how Linux rolls--almost everything else has a higher priority. The classic intrusive data structure in C is the link-list as implemented in BSD (though I'm sure it predated BSD): https://man.openbsd.org/queue#LIST_EXAMPLE

A red-black tree implemented in the same simple style by an OpenBSD developer a couple of decades later was adopted almost overnight by all BSDs: https://man.openbsd.org/tree#EXAMPLES

Unlike the Linux version, the BSD version is as type-safe as a C++ template, permits a node to exist in as many collections as you want (one member field per collection), and like a template the BSD version can inline the comparison function. You even have the option of making all the routines extern or static, which you can't even do with C++ templates.

What the Linux version has going for it is that it doesn't need to rely on the preprocessor so the implementation looks a little neater and more like a C++ template--no columns of backslashes as required with preprocessor-based generation. But that's a horrible tradeoff. queue.h and tree.h have basically been frozen for decades.[1] After initial curiosity wanes (day #2 of many thousands), nobody reads the headers because the interface is simple and never changes.

[1] Various systems have tweaked things here and there (e.g. to add parameterized trace points), but the original APIs never changed and code has always remained portable at the source level. The only big change over all that time was most systems (BSDs, macOS) eventually dropped CIRCLEQ after someone (I think a FreeBSD developer) posted benchmarks showing it sucked relative to TAILQ. I actually preferred CIRCLEQ; the entire header is small enough that for awhile I just copied it around everywhere.

Re:Go makes it easier to write correct, clear and efficient ... by rumcajz on Friday May 10, 2019 @11:12AM (#19878509)
The question of intrusive containers is kind of orthogonal. You can implement intrusive containers using generics. Aslo, kernel code would use intrusive containers even if there were easy-to-user non-intrusives available directly in C. The reason, of course, being that with intrusive containers you can avoid huge amount of memory allocations.
Re:Go makes it easier to write correct, clear and efficient ... by codr7 on Friday May 10, 2019 @05:33AM (#19876315)
You can write Fortran in any language, these people are missing the point. The simplicity is a feature, it also allows you to say exactly what you mean without sweet talking the compiler.
Re:Go makes it easier to write correct, clear and efficient ... by giornogiovanna on Friday May 10, 2019 @05:48AM (#19876385)
What should I do in Go or C if I want a red-black tree? As far as I know, my options are:

- Download one that uses interface{} / void pointers - okay, but not very efficient or type-safe.

- Download one that's intrusive - okay, but pretty convoluted.

- Write my own - a pain.

- Code generation - generics but worse.

(This isn't sarcastic.)

Re:Go makes it easier to write correct, clear and efficient ... by marcosdumay on Friday May 10, 2019 @11:58AM (#19879012)
In C you'll content yourself with a library for operations on long, long long, or void*.

But if you are working on a project where the details of the tree do not matter (so you can use a library), you will probably use C++, not C. I still have a hard time understanding what niche Go fills, it's too high level to compete with C or Rust, but here we are comparing its expressiveness with C.

Re:Go makes it easier to write correct, clear and efficient ... by foldr on Friday May 10, 2019 @06:15AM (#19876486)
Well, your list does include three practical options. Using interface{} is the go-to option and usually works fine.

The overhead of interface{} isn't as high as people sometimes think. You have the overhead of boxing the value, but the actual type checking is just a single comparison and jump.

Re:Go makes it easier to write correct, clear and efficient ... by sacado2 on Friday May 10, 2019 @06:38AM (#19876579)
> You have the overhead of boxing the value, but the actual type checking is just a single comparison and jump.

This is way too much in a tight loop. I want my structure to fit in the cache and I want to have as little tests as possible.

Re:Go makes it easier to write correct, clear and efficient ... by jerf on Friday May 10, 2019 @09:56AM (#19877706)
"This is way too much in a tight loop. I want my structure to fit in the cache and I want to have as little tests as possible."

If that is a hard requirement, then the answer is just that Go isn't a suitable language. AIUI the current generics proposal in Go, it won't fix that problem for you either.

Where I disagree with the programming community at large is how often that's actually a hard requirement. A lot of programmers grossly overestimate their performance requirements on the microscale [1], and so concerns about "premature optimization" remain alive and well decades later. However, there are undeniably still a non-trivial number of cases where that really is a hard requirement, in which case the answer is, don't use Go.

(Preferably, figure that out before you start. As a fairly heavy Go user, I actually kinda cringe when reading one of the several "We sped up Go by 10x on our particular big thing and got to barely-acceptable performance" articles, rather than consider it something to be celebrated. I mean, cool that you sped it up that much and all, but honestly the correct answer was to notice in the design phase that you were doing something you probably shouldn't have done in Go, modulo concerns about easy prototyping and such.)

[1]: I qualify with "microscale" because I also think a lot of programmers underestimate the performance requirements on the macro scale. But that's actually a very different issue. There's a lot of very sluggish and slow code out there in the wild that is architecturally wrong; at every individual step the code is reasonably optimized and fast, the problem is having the wrong steps.

Re:Go makes it easier to write correct, clear and efficient ... by foldr on Friday May 10, 2019 @07:19AM (#19876741)
Most of the time it won't actually be "too much". The comparison itself has very little overhead due to branch prediction.

But yes, if you're writing performance critical code (which you generally won't be), then you'll need to use code generation to avoid boxing.

This kind of discussion is pointless without some kind of real world reference point. The vast majority of Go projects will never run into a situation where the overhead of using interface{} is a performance bottleneck. If you're working on a project where you consistently have to think about the cache performance of your code, then C++ or Rust would probably be better choices. Go isn't meant to be all things to all people.

Re:Go makes it easier to write correct, clear and efficient ... by sacado2 on Friday May 10, 2019 @08:38AM (#19877135)
If you want a real-world example: I struggle with my SAT solver, gophersat[1].

I have different kinds of constraints, mainly propositional clauses (a or b or c) and pseudo-boolean constraints (2a + b + c >= 2). Long story short, a propositional clause is a special kind of pseudo-boolean constraint, so I can process my clauses as if they were regular pseudo-boolean constraints, but this is slower than using dedicated code.

Lots of problems only deal with propositional clauses, so they take longer to solve than they should, because I cannot say "this is a problem with only propositional clauses", vs "this is a problem with all kinds of clauses". I could use interfaces, and tried, but this is way slower, to the point it doesn't make sense to use them.

And I can't use C++ or rust for this problem: there are already tons of very good c++ SAT solvers, but my goal was to provide a SAT solver I can use in my go programs without resorting to cgo black magic.

[1]https://github.com/crillab/gophersat

Re:Go makes it easier to write correct, clear and efficient ... by foldr on Friday May 10, 2019 @08:49AM (#19877208)
Neat project.

Yes, fair enough, I think that is a good example of the kind of code that Go is not particularly suited to (if performance is critical).

Re:Go makes it easier to write correct, clear and efficient ... by eropple on Friday May 10, 2019 @09:45AM (#19877606)
> The overhead of interface{} isn't as high as people sometimes think.

The cognitive overhead certainly is. Computers exist to help us do things faster and with fewer mistakes. This is a prime example of using a computer to help us make more mistakes, worse.

Re:Go makes it easier to write correct, clear and efficient ... by foldr on Friday May 10, 2019 @10:56AM (#19878356)
Yes, using interface{} introduces a small chance of runtime type errors. I have not heard of any Go projects finding this to be much of a problem in practice. You can also use the type-safe wrapper pattern to avoid this if it's likely to be a problem.

There is no doubt that not having generics makes some code worse than it would be with generics. But I think the problem is often overstated.

Re:Go makes it easier to write correct, clear and efficient ... by bsaul on Friday May 10, 2019 @08:02AM (#19876931)
the term « boxing » was very often used before C# had proper generics, and the same goes for java when Object was used everywhere ( priori to generics). Then generics came in an everybody talked about type safety and performance gains. Then 10 years later horrendous over-complexified designs started to cripple code bases all over the world.

I honestly wonder if go isn’t cursed to follow the same road.

Re:Go makes it easier to write correct, clear and efficient ... by tluyben2 on Thursday May 16, 2019 @03:32AM (#19926907)
My Java days are long gone, but modern C# code is not overly complex and, if you use fp principles where you can, even really quite simple to read. Ofcourse you have OOP design pattern addicts who write hard to follow overarchitected stuff, but your language cannot prevent that; people write convoluted stuff in any language.

Blaming just generics for that does not work imho; in Java people were writing really insanely over complex code close after the first release; I had an ex C++ guy before 2000 writing Java code that used every design pattern in The Book, everywhere he could and it ended up with 1000s of files and those strange long names that became the standard for Java a few years later.

Re:Go makes it easier to write correct, clear and efficient ... by foldr on Friday May 10, 2019 @08:30AM (#19877064)
"Boxing" just means storing a (possibly tagged) pointer to a value rather than the value itself. It has nothing specifically to do with generics.

But yeah, I share your concern. It would be nice to have a better way to write container types in Go, but generics always seem to end up getting abused.

Re:Go makes it easier to write correct, clear and efficient ... by apta on Friday May 10, 2019 @11:19AM (#19878581)
And thru end up using clunky told like code gen to make up for the lack of generics and for mocking purposes. the resulting coffee ends up being a mess, and ironically, introduces more layers of abstraction (unnecessary interfaces just for the sake of mocking) than code bases in Java and C#
Re:Go makes it easier to write correct, clear and efficient ... by Gibbon1 on Friday May 10, 2019 @05:06AM (#19876230)
> Like C, Go lacks support for elaborate abstractions.

You can build any abstraction you want in C.

Re:Go makes it easier to write correct, clear and efficient ... by jcora on Friday May 10, 2019 @05:30AM (#19876304)
Yeah, you can write a compiler for a better language.

This is disingenuous. Show me Pi types in C.

Re:Go makes it easier to write correct, clear and efficient ... by Crinus on Friday May 10, 2019 @12:02PM (#19879059)
> Pi types in C.

I took a quick look at what these are. Couldn't they implemented with macros like (this builds a type "Utf8String" which "depends" on the value of the "ENCODING" parameter to figure out what set of functions to call for the guts of the functions that handle the type, e.g. RawStringUtf8Length):

    enum Encoding { Ascii, Utf8, Utf16 };
    
    #define TYPENAME Utf8String
    #define ENCODING Utf8
    #define CHARTYPE char
    #include "stringdef.ph"
Then in stringdef.ph (ph=parametric header, just came up with it):

    typedef struct { size_t len; CHARTYPE* text; } TYPENAME;
    
    #define MAKEFUNC(name) TYPENAME##name
    #define RAWSTRINGFUNC(name) RawString##ENCODING
    
    void MAKEFUNC(Create)(TYPENAME* str);
    void MAKEFUNC(Destroy)(TYPENAME* str);
    void MAKEFUNC(CreateFrom)(TYPENAME* str, const CHARTYPE* text);
    
    /* this goes in a single C file, single header library style */
    #ifdef IMPLEMENTATION
    
    void MAKEFUNC(Create)(TYPENAME* str) { ... }
    void MAKEFUNC(Destroy)(TYPENAME* str) { ... }
    void MAKEFUNC(CreateFrom)(TYPENAME* str, const CHARTYPE* text) {
        str->len = RAWSTRINGFUNC(Length)(text);
        str->text = RAWSTRINGFUNC(Duplicate)(text);
    }
    
    #endif
    
    #undef MAKEFUNC
    
    /* cleanup input parameters so includers wont need to do it */
    #undef CHARTYPE
    #undef ENCODING
    #undef TYPENAME
Then you can use the above simply like

    Utf8String u8s;
    Utf8StringCreateFrom(&u8s, "foo...");
It isn't exactly pretty, but seems to do the work. The ENCODING parameter is only conceptually an Encoding enum, but this can be enforced with some dummy (unused) code that does use of the ENCODING value as Encoding (and if extra strength is needed, as enums are weakly typed, instead of native enums, you could define macros that create stronger "enums" out of structs).
Re:Go makes it easier to write correct, clear and efficient ... by codr7 on Friday May 10, 2019 @05:34AM (#19876320)
Word.

Interpreter, but close enough :)

https://github.com/codr7/g-fu/tree/master/v1

Re:Go makes it easier to write correct, clear and efficient ... by jcora on Friday May 10, 2019 @06:16AM (#19876489)
This just isn't what people mean by "writing an abstraction in the language".
Re:Go makes it easier to write correct, clear and efficient ... by codr7 on Friday May 10, 2019 @08:11AM (#19876977)
I know quite a few who would consider that an option.

Embedding a higher level language that's controlled from a more primitive host language allows solving many otherwise tricky problems without the struggle.

Re:Go makes it easier to write correct, clear and efficient ... by MiroF on Friday May 10, 2019 @10:46AM (#19878248)
Reimplemented generics are all over any C codebase you might lion at.. I mean just look at the Linux kernel
Re:Go makes it easier to write correct, clear and efficient ... by codr7 on Friday May 10, 2019 @05:28AM (#19876298)
I am aware, and the same is mostly true of Go.