1. 4

    It’s much easier to convince people with a PoC than with a paper.

    1. 6

      Some would even say PoC||GTFO

      1. 1

        That’s really not how it works for most real-world vulnerabilities today.

      2. 2

        Could be dangerous to submit a PoC for this kind of thing

        1. 2

          Probably a couple of days less dangerous than submitting the paper, at best. There’s been revisions of this paper around for a while as far as I can tell. If it posed any real threat to RSA, we’d have seen something by now.

          That said, I hope I’m wrong. A world with broken RSA is a more interesting world to live in.

        2. 2

          A method of computing a factorisation more efficiently than current state of the art methods doesn’t imply that actually computing such a factorisation is cheap.

          1. 1

            There is some pseudocode in the paper. I don’t know if that counts.

            1. 2

              PoC

              Proof of concept isn’t some pseudocode for me. Proof would be an example with code you can execute to verify it along with some measured times in this case. Should be easy enough to publish some python code that can do this.

          1. 2

            I got the impression that the questionnaire is making the assumption that touch typing is better and/or faster than all alternative methods of typing.

            1. 3

              It might be, if you’re transcribing or writing, but I find that thinking/coding is not constrained by my typing speed or correction rate (~35 wpm) and my half-learned touch-typing.

              1. 3

                I touch type but don’t care about the home row. I just hit the keys I want to without sight being necessary.

                Not needing to use your eyes to type helps

                1. 3

                  The questionnaire defines touch typing as “using all the fingers and thumbs to type without looking at the keyboard.” By this definition, I touch type, because I use all of my fingers and thumbs to type, and I don’t look at the keyboard, even though my resting position bears no resemblance to the standard “home row” technique that’s usually taught. Rather, my fingers simply know where they need to be and I hit each key with whatever finger happens to be closest at the time. My accuracy isn’t brilliant, but I can sustain 60wpm corrected, and at that point, I don’t find myself limited by typing speed.

                  1. 1

                    I didn’t mean to give that impression.

                    As @Vaelatern and @thequux point out not looking at the keyboard when typing is generally more efficient. From the research I’ve found, the evidence seems to point to the minimising finger movements and setting keys so that common letter clusters can be typed by different hands seems to improve speed, accuracy and comfort. The current default staggered QWERTY layout - does not allow natural hand placement, thus increasing the risks of fatigue and injury. The default key size and spacing was design for less than 6.1% of the worlds population, I’m hoping in the near future everyone will be able to get a keyboard that is a unique fit to their bodies, and thus a pleasure to use :~)

                  1. 1

                    Why is Better Portable Graphics (BPG) by Fabrice Bellard not on the list of formats that are being compared?

                    1. 5

                      HEIC uses the same set of compression tools (HEVC/H.265’s keyframe compression) but with a different container format–both the compression pluses/minuses and the IP situation should be pretty similar.

                      1. 1

                        That makes sense, thanks.

                    1. 9

                      The nice thing about Go is that when it is verbose, like for the list deletion example, it highlights that the computer is doing more work. If you are constantly deleting items in the middle of an array (or if you’re doing this at all), it might not be the best choice of data structure.

                      1. 30

                        This sounds like a post hoc rationalization to me. You can always hide arbitrary computations behind a function call.

                        I believe this is explained by the lack of generics, and I predict that, if/when generics are implemented, go stdlib will gain a bunch of slice-manipulating functions a-la reverse.

                        1. 2

                          Which is probably one of the stronger arguments for genetics.

                          1. 2

                            This sounds like a post hoc rationalization to me.

                            This was always pretty reliably cited as the motivation for a lot of design decisions, back when Go was just released.

                            You can always hide arbitrary computations behind a function call.

                            Yes, but one nice thing about Go is that functions are essentially the only way to hide arbitrary computation. (And, relatedly, the only mechanism that Go has to build abstraction.) When you’re reading code, you know that a + b isn’t hiding some O(n²) bugbear. That’s valuable.

                            1. 3

                              Yup, I agree with the general notion that reducing expressive power is good, because it makes the overall ecosystem simpler.

                              But the specific example with list manipulation is “a wrong proof of the right theorem”, and this is what i object to.

                              Incidentally, a + b example feels like a wrong proof to me as well, but for a different reason. In Go, + can also mean string concatenation, so it can be costly, and doing + in a linear loop can be accidentally quadratic. (I don’t write Go, might be wrong about this one).

                              1. 1

                                In Go, + can also mean string concatenation, so it can be costly

                                How do you mean? String concatenation is O(1)…

                                doing + in a linear loop can be accidentally quadratic. (I don’t write Go, might be wrong about this one).

                                How’s that?

                                1. 2

                                  String concatenation is O(1)…

                                  Hm, I don’t think that’s the case, seem to be O(N) here:

                                  
                                  14:48:36|~/tmp
                                  λ bat -p main.go 
                                  package main
                                  
                                  import (
                                      "fmt"
                                      "time"
                                  )
                                  
                                  func main() {
                                      for p := 0; p < 10; p++ {
                                          l := 1000 * (1 << p)
                                          start := time.Now()
                                          s := ""
                                          for i := 0; i < l; i++ {
                                              s += "a"
                                          }
                                          elapsed := time.Since(start)
                                          fmt.Println(len(s), elapsed)
                                      }
                                  }
                                  
                                  14:48:40|~/tmp
                                  λ go build main.go && ./main 
                                  1000 199.1µs
                                  2000 505.49µs
                                  4000 1.77099ms
                                  8000 3.914871ms
                                  16000 14.675162ms
                                  32000 49.782358ms
                                  64000 182.127808ms
                                  128000 661.137303ms
                                  256000 2.707553408s
                                  512000 11.147772027s
                                  
                                  1. 3

                                    You’re right! O(N). Mea culpa.

                          2. 40

                            it highlights that the computer is doing more work

                            It seems strange to me to trust in the ritual of doing strange and obnoxius, bug-prone, programming to reflect the toil the computer will be burdened with. Doubly strange when append() is generic magical go function built-in which can’t be implemented in Go so it’s hard to even say, without disassembly and studying the compiler, what the code would even end up doing at runtime; I guess we can make very good educated guesses.

                            1. 20

                              IMHO, no performance concerns are valid* until a profiler is run. If it wasn’t run, the program was fast enough to begin with, and if it was, you’ll find out where you actually have to optimise.

                              • Exception: if there are two equally readable/maintanable ways to write code, and one is faster than the other, prefer the faster version. Otherwise, write readable code and optimise when/if needed.
                              1. 4

                                I feel this statement is a bit too generic, even with the exception. Especially when you’re talking about generic stdlib(-ish) functions that may be used in a wide variety of use cases, I think it makes sense to preëmptively think about performance.

                                This doesn’t mean you should always go for the fastest possible performance, but I think it’s reasonable to assume that sooner or later (and probably sooner) someone is going to hit some performance issues if you just write easy/slow implementations that may be “fast enough” for some cases, but not for others.

                              2. 18

                                But I want the computer to be doing the work, not me as human source code reader or, worse, source code writer.

                                1. 1

                                  Sure, but a language that hides what is computationally intensive or not, is worse.

                                  1. 24

                                    Source code verbosity is poorly correlated with runtime cost, e.g. bubble sort code is shorter and simpler than other sorting algorithms.

                                    Even in the case of removing items from arrays, if you have many items to remove, you can write a tiny loop with quadratic performance, or write longer, more complex code that does extra bookkeeping to filter items in one pass.

                                    1. 6

                                      Then don’t build your language to hide what’s computationally expensive. Fortunately, most languages don’t do any sort of hiding; folding something like list deletion into a single function call is not hiding it - so this statement isn’t relevant to the discussion about Go (even if true in a vacuum). Any function or language construct can contain any arbitrary amount of computational work - the only way to know what’s actually going on is to read the docs, look at the compiler, and/or inspect the compiled code. And, like @kornel stated, “Source code verbosity is poorly correlated with runtime cost”.

                                    2. 1

                                      As a user, I don’t want the computer to be doing the work. It reduces battery life.

                                      1. 10

                                        If you’re referring to compilation or code-generation - that work is trivial. If you’re referring to unnecessary computation hidden in function calls - writing the code by hand is an incredibly bad solution for this. The correct solutions include writing efficient code, writing good docs on code to include performance characteristics, and reading the function source code and/or documentation to check on the performance characteristics.

                                        As @matklad said, “You can always hide arbitrary computations behind a function call.”e

                                  1. 29

                                    One thing I don’t think I’m ever going to get is how much Go does in comments. In my mind, comments are a way to communicate something to other humans, or, sometimes, a way to communicate something to some external tool (such as a documentation generator). However, in Go, you configure whether the file should be built in comments, you write C code in comments with CGo, you write shell commands for code generation in comments, and, with 1.16, you embed data into your binary using comments.

                                    I’m all for a kind of extensible meta language; a way to have commands in the code which the compiler proper will skip, but which official tooling might interpret. Something like a #pragma. But… in my mind, the official language toolchain shouldn’t extensively parse my comments.

                                    On the positive side though, I think what embed does is really cool. More languages should have a way to embed arbitrary data into the binary (without hacks).

                                    1. 17

                                      If it helps, you can consider the string //go: to be equivalent to the string #pragma and not think of it as a comment. Reusing the comment syntax has the advantage that parsers/formatters don’t have to worry about parsing anything other than comments. Much like how a shebang (#!/usr/bin/env bash) happens to be a comment in a bunch of scripting languages.

                                      1. 17

                                        Yea, if it was only that, I wouldn’t have been too worried. However, you also have a case where a comment changes the semantics of the following import after the comment. The whole thing seems like a giant hack to me; like “changing the grammar is too much work, so we’ll just make the tooling parse your comments so we don’t have to change the compiler”. I’m not saying that’s how the process is; I’m saying that’s how it feels as an observer.

                                        I would’ve probably done something like C, where lines starting with # are obviously going to be interpreted differently from other lines. The compiler could ignore all lines starting with #, so that the tooling could add new directives in a backwards-compatible way, and parsers/formatters could largely ignore them. It just would’ve been a structured thing instead of essentially parsing prose.

                                        1. 10

                                          The whole thing seems like a giant hack to me; like “changing the grammar is too much work, so we’ll just (…)

                                          This is how I feel about imports as strings. I see no good reason why we need quotation marks around the import paths in Go, it should be obvious for a parser how to deal with a path there. In general the Go syntax is… inconsistent at best.

                                          1. 2

                                            I see no good reason why we need quotation marks around the import paths in Go

                                            This is a guess, but it may be to make plumbing easier in Plan 9/Acme. Syntax like <something> and "something" is easier to match than just something.

                                            1. 1

                                              I think the comment you’re replying to is arguing that it’s not just "something" vs. something, but import "something" vs. import something.

                                              1. 2

                                                Yeah, I know, but multiple imports still need quotation marks to be plumbable:

                                                import (
                                                    "path/to/package1"
                                                    "path/to/package2"
                                                )
                                                

                                                works, whereas

                                                import (
                                                    path/to/package1
                                                    path/to/package2
                                                )
                                                

                                                wouldn’t.

                                                1. 2

                                                  Not sure why that would be the case. the plumber gets the whole string either way, expanded out to the surrounding whitespace if there’s no selection.

                                                  1. 3

                                                    But the plumber has to know somehow that it is a Go import path. The quotation mark syntax in Go (and C) makes that clear.

                                                    For example, should test, without quotes, really be treated as a Go/C import path? Wouldn’t that be too broad a rule?

                                                    1. 1

                                                      The plumber also gets a bunch of context, like the place you plumbed from. It should use that.

                                            2. 2

                                              I thought the same at first, but it’s simpler for the lexer/tokenizer to not have to know what mode it’s in. It’ll (presumably) just output a STRING token, and it’s only the parser that has to know that it’s in an import directive. Go is partly about keeping parsing (and lexing) simple and fast.

                                            3. 6

                                              It’s not my most favourite syntax either, but using #pragma or //go: seems like a really minor issue. I’m not sure what the motivation was for choosing //go: over # or #pragma.

                                              a case where a comment changes the semantics of the following import after the comment

                                              I assume you mean package foo // import "bar" type comments? That one, in particular, was a mistake IMO. But also kind of obsoleted by modules, and not really related to //go: directives.

                                              1. 1

                                                I don’t know what package foo // import "bar" does. Could you elaborate on it?

                                                I was talking mostly about CGo, where you have a giant comment with a mix of C code and #cgo pseudo-directives followed by a line with import "C", where the comment (minus the #cgo lines) is compiled by a C compiler and linked with the binary.

                                                1. 3

                                                  It enforces that the package is imported as bar; often used for “vanity paths”; e.g. lobste.rs/mypkg instead of github.com/lobsters/mypkg. This prevents some problem where one dependency might use the lobste.rs path, and the other the github.com path. It’s a bit of a hack, and you can do the same with a go.mod file now.

                                                  cgo is kind of a tricky beast, yeah; but also fairly rare. And since you can write any C code in that comment, I’m also not sure how else to do it? Overall, it seems to work fairly well and in the grand scheme of things, it seems like a fairly minor issue to me.

                                          2. 37

                                            But it’s a great way to pretend that it’s a small language with few reserved words.

                                            1. 7

                                              Even with the comment syntax, Go has fewer reserved words than C.

                                              1. 7

                                                While I agree with your comment, it’s a non sequitur. Having fewer reserved words and being a smaller language are two different things. LISP has 0 reserved words, therefore it must be the smallest language, right?

                                                1. 4

                                                  Go is still a small language.

                                            2. 3

                                              This is the long-standing rationale for not having comments in JSON, and I think it stands the test of time (and complaints of programmers).

                                              1. 16

                                                This was just paternalistic nonsense on Crockford’s part. While I don’t really understand the Go author’s decision to use comments for pragmas, I would never in my life give up all comments to put a stop to it. An absolute textbook example of cutting off one’s nose to spite one’s face.

                                                1. 16

                                                  I think it makes perfect sense for JSON’s intended usage as a data interchange format with good interoperability between all sorts of different environments. Extensions have made this much harder than it needs to be on more than a few occasions in the past.

                                                  Now, if you want to use JSON for your config files then sure, it’s annoying. But that wasn’t the intended usage. If you’re driving a square peg through a round hole then you shouldn’t really complain about the peg shape but get a different peg instead.

                                                  1. 7

                                                    I still don’t buy it. If we’re considering the intended usage, one of the goals that gets thrown around is that it is “easy for humans to read and write” – just as long as they never need to convey something to another human being in the form of a comment!

                                                    There are so many other under-specified parts of JSON, like what to do with large integers, or what happens when a document contains duplicate keys. It is extremely frustrating that comments were intentionally and unnecessarily stripped out, while the hard problems were apparently just ignored.

                                                    1. 8

                                                      HTTP or SMTP are easy for humans to read and write, and don’t have comments either because in the intended usage space it’s not really needed. Like those data formats, JSON is primarily intended to send text from one program to the other, and the “easy for humans to read and write” is more as a debugging and testing aid than anything else.

                                                      There are so many other under-specified parts of JSON, like what to do with large integers, or what happens when a document contains duplicate keys. It is extremely frustrating that comments were intentionally and unnecessarily stripped out, while the hard problems were apparently just ignored.

                                                      Sure, it could be improved, maybe, but as you mention these are not easy things to define in a compatible way since different languages deal with these things in different ways. But I don’t think that’s a good reason to introduce more interoperability issues.

                                              2. 2

                                                The comment syntax is mainly used together with cgo. Including a header instead of inlining C makes it feel less hacky and allows for syntax highlighting of the C code for a larger range of editors: // #include "project.h".

                                                1. 2

                                                  IIRC there was discussion of adding pragma syntax, but it was decided that it’s not worth it to add yet another syntax, since there already existed comment-based pragmas that would have to be kept because of the go 1 compat promise.

                                                1. 1

                                                  FreeBSD 12.2-RELEASE sounds like a sudden surprise. I believe there’s a typo in the title.

                                                  1. 1

                                                    I’ve seen people struggle with the transition from front-end to embedded. The way of thinking is different, it requires a different skillset, and there is little respect to be had when people come from a web background. I don’t think the transition would be complete until after building skills a couple of years in one company, then switching to another.

                                                    1. 3

                                                      Reading the Clojure solution involves following the thought process of how the author ended up there. Reading the equivalent Go solution has very little cognitive overhead.

                                                      How does Clojure programmers write code that is not just brief and elegant in the eyes of the author, but can also be read quickly by others without time consuming mental gymnastics?

                                                      1. 4

                                                        I guess it’s just a matter of what you’re used to. I find both Go solutions above arduous to understand because you have to follow the algorithm and construct what it functionally does in your head. Whereas in most of the clojure solutions the code directly tells you what’s happening. Eg. the top post with comments:

                                                        ; threading macro (take input, then do stuff to it in steps)
                                                        (->> "aaaabbbcca"
                                                             ; split into lists of consecutive same character
                                                             (partition-by identity)
                                                             ; map each item (list of chars) with a function
                                                             (map 
                                                               ; return list of outputs of functions
                                                               (juxt 
                                                                 ; first character as string
                                                                 (comp str first)
                                                                 ; count of characters
                                                                 count)))
                                                        

                                                        The information is much more dense. If you are good at reading it, you understand it at a glance.

                                                        I believe the same is true for the APL solutions. I can’t read them, but someone who does sees the algorithm clearly.

                                                        1. 5

                                                          I find both Go solutions above arduous to understand

                                                          Same here; they just seem super tedious and low-level; like you’re spoon-feeding the compiler on basic things instead of just describing the algorithm naturally.

                                                          If you don’t have the vocabulary to describe an algorithm, of course the low-level version is going to be easier to read, much like someone who is only just learning English will find the “Simplified English” wikipedia more accessible than the regular one that often uses specialized jargon. But if you work with algorithms every day, you owe it to yourself to invest in learning the jargon!

                                                          1. 1

                                                            Isn’t this just because Clojure has a much bigger standard library than Go? I’m sure the Go solutions would be much higher level if you allowed for third party packages.

                                                            1. 3

                                                              I don’t think it has to do with the size necessarily but rather the focus on sequence manipulation as a core competency; the acknowledgement that data structures are at the center of what languages need to be good at.

                                                              Allowing 3rd-party packages would make it shorter at the expense of readability; you can’t assume your reader is familiar with idioms outside the language.

                                                            2. 1

                                                              Lower level also means that it’s closer to what’s happening on the computer when the code is running. Depending on the type of program, this can be useful.

                                                          2. 2

                                                            Sort of the same principle as how people can jump into a rails codebase that’s got thousands of classes and be productive quickly.

                                                            It’s a lot of convention, and a lot of practice.

                                                            That Clojure code is also very Clojure-y if you know what I mean, it’s not doing anything clever or obscure.

                                                            You might benefit from looking over some style guides and really reflecting how your code reads in the lens of what the style guide says.

                                                            1. 2

                                                              That’s a great question and it basically boils down to good taste. You can do code golfing and try to get the code as small and concise as possible, or you can write it the laborious but obvious way. This goes for any language with abstractions, you can always go too far in using certain abstractions. Nowadays I lean more towards “dumb” code because it’s not just easier to write but also easier to understand. However, the “code golf” style solution can be more robust. “Dumb” code tends to have more edge cases (i.e. bugs).

                                                              I like how the above short go code deals with the starting letter edge case by simply prefixing the string; I struggled a bit with that myself as I was coming up with a solution. Now that I think about it, there’s an edge case that gets triggered if the first character in the string is a space; then the code crashes.

                                                            1. 2

                                                              I know this is a Clojure post, but out of curiosity I wrote it in Go (what I’ve been working in lately) just to see if I could solve it quickly. Took about 10 minutes, subtract 3-4 for fighting with runes:

                                                              package main
                                                              
                                                              import "fmt"
                                                              
                                                              type result struct {
                                                              	letter string
                                                              	count  int
                                                              }
                                                              
                                                              func main() {
                                                              	const input = "aaaabbbcca"
                                                              
                                                              	var ret []result
                                                              	currentLetter := string(input[0])
                                                              	countCurrentLetter := 1
                                                              
                                                              	for _, elem := range input[1:] {
                                                              		elemAsString := string(elem)
                                                              		if currentLetter == elemAsString {
                                                              			countCurrentLetter++
                                                              		} else {
                                                              			ret = append(ret, result{currentLetter, countCurrentLetter})
                                                              			currentLetter = elemAsString
                                                              			countCurrentLetter = 1
                                                              		}
                                                              	}
                                                              
                                                              	ret = append(ret, result{currentLetter, countCurrentLetter})
                                                              
                                                              	fmt.Printf("%+v", ret)
                                                              }
                                                              

                                                              It’s not particularly elegant, but it works.

                                                              1. 2

                                                                It’s not particularly elegant, but it works.

                                                                That’s my problem with many other (non-Lispy) languages. The programs are not elegant, even though they do work. What works for a computer, don’t always work for me.

                                                                1. 1

                                                                  Here’s my take on it. It took me (roughly) the same 8-10 minutes to type it in the web-ui. In Emacs I could shave some time off of it.

                                                                  type tuple struct {
                                                                  	s string
                                                                  	i int
                                                                  }
                                                                  
                                                                  func splitStringReturnTuples(str string) []tuple {
                                                                  	str = " " + str
                                                                  	res := []tuple{}
                                                                  	for i := 1; i < len(str); i++ {
                                                                  		if str[i] != str[i-1] {
                                                                  			res = append(res, tuple{string(str[i]), 1})
                                                                  		} else {
                                                                  			res[len(res)-1].i++
                                                                  		}
                                                                  	}
                                                                  	return res
                                                                  }
                                                                  

                                                                  Runnable code at the go playground

                                                                  1. 2

                                                                    This loops over the bytes in the string instead of the runes in the string. Try inserting a multi-byte rune such as 本 in the string, and see what happens.

                                                                    1. 2

                                                                      The problem statement clearly stated the data set, there was no multi-byte symbols. But the tweet gave a clear understanding that interviewer expects solution to be give in a limited time frame. Therefore the solution was provided in terse notation with abbreviated variables taking provided test input and returning expected output. Not more nor less.

                                                                      But point is taken. Here’s the code correctly handling multi-byte encodings. The logic is the same, but the part of casting passed string into a slice of runes.

                                                                      When I interview people I don’t expect them to write code perfectly handling every possible input in the limited time. What I’m interested in first, if they are able to come up with straightforward solution leveraging data structures and algorithms helping them solve the problem with optimal complexity. Second, if they can clearly communicate their approach. And coding comes third.

                                                                      1. 2

                                                                        That makes sense. I did not mean to criticize your solution in particular, just highlight that this is a common “gotcha” in Go. Casting strings to []rune or looping with for _, r := range str is, as far as I know, the only built-in way to access the letters in strings correctly. I’ve seen many problems arise from assuming that str[x] returns a rune instead of a byte. I think it would be more useful and intuitive if []byte(str)[x] was needed to return a byte, while just str[x] could be used to return a rune.

                                                                1. 7

                                                                  The idea of just being able to pipe any list in and then select an item in a quick an beautiful way is a great one. The integration with zsh, vim, tmux and other established programs also makes it more attractive. I use fzf daily.

                                                                  1. 2

                                                                    I personally prefer percol because it does just what you describe in the first sentence. Well, and because it was already my most used command before others exist. I find some of fzf extra features useful, but it goes a bit too much over the edge on integrations and whatnot.

                                                                  1. 7

                                                                    I don’t want to 💩on the author’s writeup here, because it is a decent one. I’m using it to launch another public objection to Go Generics.

                                                                    A lot of proposals for and write ups about Go Generics seem to miss that there’s a very large group of Go users who object to Generics, and for good reason. It’s not because this group questions the efficacy of generics in solving very specific problems very well – objectors are generally well attuned to Generics’ utility. What’s objected to is the necessity of Generics. The question that we pose is do we need generics at all? Are the problems that Generics solve so important that Generics should pervade the language?

                                                                    From the author’s conclusion

                                                                    I was able to solve a problem in a way that was not previously possible.

                                                                    Being able to solve problems in new ways isn’t always valuable; it can even be counter-productive.

                                                                    1. 24

                                                                      Nothing is necessary except an assembler. Well, you don’t even need the assembler, you can just flip the bits yourself.

                                                                      Go has an expressiveness gap. It has some kind of big classes of algorithms that can’t be made into libraries in a useful way. Most people advocate just rewriting basically the same code over and over forever, which is kind of crazy and error-prone. Other people advocate code-generation tools with go generate, which is totally crazy and error-prone, even with the decent AST tools in the stdlib. Generics close the gap pretty well, they’re not insanely complex, and people have had decades to get used to them. If you don’t want to use them yourself, don’t use them, but accept that there are people for whom, say, the ability to just go get a red-black tree implementation that they can use with a datatype of their own choosing, without loss of type-safety or performance, will greatly improve the usefulness of the language.

                                                                      Plus, from a purely aesthetic standpoint, it always seemed criminal to me to have a language that has first-class functions, and lexical closure, but in which you can’t even write map because its type is inexpressible.

                                                                      1. 9

                                                                        Go has an expressiveness gap.

                                                                        That’s true. You’ve identified some of the costs. Can you identify some of the benefits, too?

                                                                        1. 12

                                                                          Easy: not having a feature protects you from bright idiots that would misuse it.

                                                                          Honestly though, that’s the only argument I can make against generic. And it’s not even valid, because you could say this about almost any feature. It’s a fully general counter argument: give people hammers, some will whack each other’s heads instead of hitting nails.

                                                                          Assuming basic competency of the users and assuming they were designed from the ground up, generics have practically no downsides. They provide huge benefits at almost no marginal cost. There is a sizeable up-front cost for the language designer and the compiler writer, but they were willing to pay that kind of price when they set out to build a general purpose languages, didn’t they?

                                                                          1. 2

                                                                            They provide huge benefits at almost no marginal cost.

                                                                            If this huge benefit is only one in a minor part of the project, or even, in a minority of projects, then it has to be balanced and thought through.

                                                                            Right now, I don’t know many people that work Go daily, telling me that not having generics makes their day a pain.

                                                                            Most of them told me that it’s sometimes painful, but that’s actually pretty rare.

                                                                            There is a sizeable up-front cost for the language designer and the compiler writer, but they were willing to pay that kind of price when they set out to build a general purpose languages, didn’t they?

                                                                            Is the burden really on them? To me the it is on the program writer.

                                                                            1. 8

                                                                              There’s likely a survivorship bias going on there.

                                                                              I used Go as a programming language for my side projects for years. The thing that finally got me to give it up was the lack of generics. In writing PISC, the way I had approached it in Go ended up causing a lot of boilerplate for binding functions.

                                                                              Go is something I’d happily write for pay, but I prefer expressiveness for my side projects now, as the amount of effort that goes into a side project is a big determining factor in how much I can do in one

                                                                              1. 3

                                                                                There is a sizeable up-front cost for the language designer and the compiler writer, but they were willing to pay that kind of price when they set out to build a general purpose languages, didn’t they?

                                                                                Is the burden really on them? To me the it is on the program writer.

                                                                                Assuming we are a collaborative species (we mostly are, with lots of exceptions), then one of our goals should be minimizing total cost. Either because we want to spend our time doing something else, or because we want to program even more stuff.

                                                                                For a moderately popular programming language, the users will far outnumber and outproduce the maintainers of the language themselves. At the same time, the languages maintainers’ work have a disproportionate impact on everyone else. To such a ludicrous extent in fact that it might be worth spending months on a feature that would save users a few seconds per day. Like compilation speed.

                                                                                Other stuff like generic will affect fewer users, but (i) it will affect them in a far bigger way than shaving off a few seconds of compilation time would have, and (ii) those particular users tend to be library writers, and as such they will have a significant impact on the rest of the community.

                                                                                So yes, the burden really is on the language creators and compiler writers.


                                                                                Note that the same reasoning applies when you write more mundane software, like a train reservation system. While there is rarely any monetary incentive to make that kind of thing not only rock solid, but fast and easy to work with, there is a moral imperative not to inflict misery upon your users.

                                                                            2. 5

                                                                              I haven’t used Go in anger but here are some benefits from not including generics.

                                                                              • Generics are sometimes overused, e.g. many C++ libraries.
                                                                              • The type system is simpler.
                                                                              • The compiler is easier to implement and high quality error messages are easier to produce.
                                                                              • The absence of generics encourages developers to use pre-existing data structures.
                                                                            3. 2

                                                                              If red-black trees and map were just built in to Go, wouldn’t that solve 90% of the problem, for all practical purposes?

                                                                              What I really miss in Go is not generics, but something that solves the same problems as multiple dispatch and operator overloading.

                                                                              1. 3

                                                                                Sort of, but no. There’s too many data structures, and too many useful higher-order functions, to make them all part of the language. I was just throwing out examples, but literally just a red-black tree and map wouldn’t solve 90% of the problem. Maybe 2%. Everyone has their own needs, and Go is supposed to be a small language.

                                                                                1. 1

                                                                                  Data structures and higher-order functions can already be implemented in Go, though, just not by using generics as part of the language.

                                                                            4. 15

                                                                              Technically Go does have generics, they just aren’t exposed to the end developer, except in the form of the builtin map and array types, and are only allowed for internal developers. So in a sense, Go does need generics and they already pervade the language.

                                                                              I don’t personally have a horse in this race and don’t work with Go, but from a language-design perspective it does seem strange to limit user-developed code in such a way. I’d be curious what your thoughts on why this discrepancy is OK and why it shouldn’t be fixed by adding generics to the language.

                                                                              1. 14

                                                                                I don’t personally have a horse in this race and don’t work with Go, but from a language-design perspective it does seem strange to limit user-developed code in such a way.

                                                                                Language design is all about limiting user defined code to reasonable subsets of what can be expressed. For a trivial example, why can’t I name my variable ‘int’? (In Myrddin, as a counterexample, var int : int is perfectly legal and well defined).

                                                                                For a less trivial example, relatively few languages guarantee tail recursion – this also limits user developed code, and requires programmers to use loops instead of tail recursion or continuation passing style.

                                                                                Adding generics adds a lot of corner cases to the type system, and increases the complexity of the language a good deal. I know. I implemented generics, type inference, and so on in Myrddin, and I’m sympathetic to leaving generics out (or, as you say, extremely limited) to put a cap on the complexity.

                                                                                1. 3

                                                                                  I see only two legitimate reasons to limit a user’s capabilities:

                                                                                  1. Removing the limitation would make the implementer’s life harder.
                                                                                  2. Removing the limitation would allow the user to shoot themselves in the foot.

                                                                                  Limiting tail recursion falls squarely in (1). There is no way that guaranteeing tail recursion would cause users to shoot themselves in the foot. Generics is another matter, but I strongly suspect it is more about (1) than it is about (2).

                                                                                  Adding generics adds a lot of corner cases to the type system, and increases the complexity of the language a good deal.

                                                                                  This particular type system, perhaps. This particular language, maybe. I don’t know Go, I’ll take your word for it. Thing is, if Go’s designers had the… common sense not to omit generics from their upcoming language, they would have made a slightly different language, with far fewer corner cases they will inevitably suffer now that they’re adding it after the fact.

                                                                                  Besides, the complexity of a language is never a primary concern. The only complexity that matters is that of the programs written in that language. Now the complexity of a language does negatively impact the complexity of the programs that result from it, if only because language space is bigger. On the other hand, this complexity has the potential to pay for itself, and end up being a net win.

                                                                                  Take C++ for instance. Every single feature we add to it increases the complexity of the language, to almost unbearable levels. I hate this language. Yet, some of its features definitely pay for themselves. Range for for instance, while it slightly complicates the language, makes programs that use it significantly cleaner (although only locally). That particular feature definitely pays for itself. (we could discuss other examples, but this one has the advantage of being uncontroversial.)

                                                                                  As far as I can tell, generics tend to massively pay for themselves. Not only do they add flexibility in many cases, they often add type safety (not in C++, they don’t). See for instance this function:

                                                                                  foo : (a -> b) -> [a] -> [b]
                                                                                  

                                                                                  This function has two arguments (where a and be are unknown types): a function from a to b, and a list of a. It returns a list of b. From this alone, there is a lot we can tell about this function. The core idea here is that the body of the function cannot rely on the contents of generic types. This severely constraints what it can do, including the bugs it can have.

                                                                                  So, when we write let ys = foo f xs, here’s what we can expect before we even look at the source code:

                                                                                  • Assuming f is of type a->b, then xs is a list of a, and the result ys is a list of b.
                                                                                  • The elements of ys, if any, can only come from elements of xs.
                                                                                    • And they must have gone through f.
                                                                                    • Exactly once.
                                                                                  • The function f itself does not affect the number or order of elements in the result ys
                                                                                  • The elements of xs do not individually affect the number or order of elements in the result ys
                                                                                  • The only thing that affects the number or order of elements in the result ys is the size of xs (and the code of foo, of course).

                                                                                  This is quite unlike C++, or other template/monomorphisation approaches. Done right, generics have the opportunity to remove corner cases in practice. Any language designer deciding they’re not worth their while better have a damn good explanation. And in my opinion, the explanations offered for Go weren’t satisfactory.

                                                                                  1. 4

                                                                                    Complexity of a language is the primary concern!

                                                                                    Languages are tools to express ideas, but expressiveness is a secondary concern, in the same way that the computer is the secondary audience. Humans are the primary audience of a computer program, and coherence is the primary concern to optimize for.

                                                                                    Literary authors don’t generally invent new spoken languages because they’re dissatisfied with the expressive capability of their own. Artful literature is that which leverages the constraints of it’s language.

                                                                                    1. 4

                                                                                      Literary authors don’t generally invent new spoken languages because they’re dissatisfied with the expressive capability of their own. Artful literature is that which leverages the constraints of it’s language.

                                                                                      Eh, I have to disagree here. Literary authors try to stretch and cross the boundaries the of their spoken languages all the time, specifically because they search ways to express things that where not yet expressed before. To give some uncontroversial examples, Shakespeare invented 1700 new words and Tolkien invented not one, but a couple of whole new languages.

                                                                                      I am but a very low level amateur writer, but I can tell you: the struggle with the tool to express your ideas is as real with spoken languages as it is with programming languages. It is an approach from another direction, but the results from spoken languages turn out to be as imperfect as those from programming ones.

                                                                                      1. 1

                                                                                        I’d argue that constrained writing is more common, if nothing else than showing ones mastery of a shared language is more impressive than adding unknown elements.

                                                                                        Tolkien’s Elvish languages, while impressively complete, are simply used as flavor to the main story. The entire narrative instead leans heavily on tropes and language patterns from older (proto-English) tales.

                                                                                        1. 1

                                                                                          Yes, you have a point. I mentioned Tolkien because that was the first writer that created a new language that I could come up with. But in the end, if you want to express an idea, then your audience must understand the language that you use, otherwise they will not get your message. So common language and tropes can help a lot.

                                                                                          However, I think your mention of constrained writing is interesting. Because in a way, that Go does not have generics, is similar to the constraint that a sonnet must follow a particular scheme in form and content. It is perfectly possible to add generics to Go, the same way as it is very possible to slap another tercet at the end of a sonnet. Nothing is stopping you, really, Expect that then it would no longer be a sonnet. Is that a bad thing? I guess not. But still almost no-one does it.

                                                                                          I’d say that the rules, or the constraints, are a form of communication too. If I read a sonnet, I know what to expect. If I read Go, I know what to expect. Because some things are ruled out, there can be more focus on what is expressed within the boundaries. As a reader you can still be amazed. And, the same as in Go, if what you want to express really does not fit in the rules of a sonnet, or if it is not worth the effort to try it, then you can use another form. Or another programming language.

                                                                                        2. 1

                                                                                          Your points don’t conflict with my points, and I agree with them.

                                                                                        3. 2

                                                                                          Can we agree that the goal of programming languages is to reduce costs?

                                                                                          • Cost of writing the program.
                                                                                          • Cost of errors that may occur.
                                                                                          • Cost of correcting those errors.
                                                                                          • Cost of modifying the program in the face of unanticipated new requirements.

                                                                                          That kind of thing. Now we must ask what influences the costs. Now what about increased expressiveness?

                                                                                          A more expressive language might be more complex (that’s bad), more error prone (that’s bad), and allow shorter programs (that’s good), or even clearer programs (that’s good). By only looking at the complexity of the language, you are ignoring many factors that often matter a whole lot more.

                                                                                          Besides, that kind of reasoning quickly breaks down when you take it to its logical extreme. No one in their right mind would use the simplest language possible, which would be something like the Lambda Calculus, or even just the iota combinator. Good luck writing (or maintaining!) anything worth writing in those.

                                                                                          Yes, generics makes a language more complex. No, that’s not a good enough argument. If it was, the best language would only use the iota combinator. And after working years in a number of languages (C, C++, OCaml, Ptython, Lua…), I can tell with high confidence that generics are worth their price several orders of magnitudes over.

                                                                                          1. 2

                                                                                            I agree with you that generics can be hugely net positive in the cost/benefit sense. But that’s a judgment that can only be made in the whole, taking into account the impact of the feature on the other dimensions of the language. And that’s true of all features.

                                                                                            1. 1

                                                                                              Just popping in here because I have minimal experience with go, but a decent amount of experience in languages with generics, and I’m wondering: if we set aside the implementation challenge, what are some examples of the “other dimensions” of the language which will be negatively impacted by adding generics? Are these unique to go, or general trade offs in languages with generics?

                                                                                              To frame it in another way, maybe a naive take but I’ve been pretty surprised to see generics in go being rejected due to “complexity”. I agree that complexity ought to be weighed against utility but can we be a little more specific? Complexity of what specifically? In what way will writing, reading, compiling, running, or testing code become more complicated when my compiler supports generics. Is this complexity present even if my own code doesn’t use generics?

                                                                                              And just a final comparison on language complexity. I remember when go was announced, the big ticket feature was its m:n threaded runtime and support for CSP-style programming. These runtimes aren’t trivial to implement, and certainly add “complexity” via segmented stacks. But the upside is the ability to ergonomically express certain kinds of computational processes that otherwise would require much more effort in a language without these primitives. Someone decided this tradeoff was worth it and I haven’t seen any popular backlash against it. This feature feels very analogous to generics in terms of tradeoffs which is why I’m so confused about the whole “complexity” take. And like, maybe another naive question, but wouldn’t generics be significantly less tricky to implement than m:n threads?

                                                                                              1. 5

                                                                                                It isn’t just implementation complexity of generics itself. It’s also sure to increase the complexity of source code itself, particularly in libraries. Maybe you don’t use generics in your code, but surely some library you use will use generics. In languages that have generics, I routinely come across libraries that are more difficult to understand because of their use of generics.

                                                                                                The tricky part is that generics often provides some additional functionality that might not be plausible without it. This means the complexity isn’t just about generics itself, but rather, the designs and functionality encouraged by the very existence of generics. This also makes strict apples-to-apples comparisons difficult.

                                                                                                At the end of the day, when I come across a library with lots of type parameters and generic interfaces, that almost always translates directly into spending more time understanding the library before I can use it, even for simple use cases. That to me is ultimately what leads me to say that “generics increases complexity.”

                                                                                                1. 2

                                                                                                  what are some examples of the “other dimensions” of the language which will be negatively impacted by adding generics?

                                                                                                  From early golang blog posts I recall generics add substantial complexity to the garbage collector.

                                                                                                  The team have always been open about their position (that generics are not an early priority, and they will only add them if they can find a design that doesn’t compromise the language in ways they care about). There have been (numerous proposals rejected)[https://github.com/golang/go/issues?page=3&q=generics++is%3Aclosed+label%3AProposal] for varied reasons.

                                                                                                  Someone decided this tradeoff was worth it and I haven’t seen any popular backlash against it

                                                                                                  There’s no backlash against features in new languages, because there’s nobody to do the backlash.

                                                                                                  Go has already got a large community, and there’s no shortage of people who came to go because it was simple. For them, adding something complex to the language is frightening because they have invested substantial time in an ecosystem because of its simplicity. Time will tell whether those fears were well-founded.

                                                                                            2. 1

                                                                                              No, expressiveness is the only reason for languages to exist. As you say, humans are the primary audience. With enough brute force, any language can get any task done, but what we want is a language that aids the reader’s understanding. You do that by drawing attention to certain parts of the code and away from certain parts, so that the reader can follow the chain of logic that makes a given program or function tick, without getting distracted by irrelevant detail. A language that provides the range of tools to let an author achieve that kind of clarity is expressive.

                                                                                              1. 2

                                                                                                I think we are using “expressive” differently. Which is fair, it’s not really a well-defined term. But for me, expressiveness is basically a measure of the surface area of the language, the features and dimensions it offers to users to express different ideas, idioms, patterns, etc. Importantly, it’s also proportional to the number of things that it’s users have to learn in order to be fluent, and most of the time actually exponentially proportional, as emergent behaviors between interacting features are often non-obvious. This is a major cost of expressiveness, which IMO is systemically underestimated by PLT folks.

                                                                                            3. 3

                                                                                              I implemented generics. You’re trying to convince me that it’s worth implementing generics. Why?

                                                                                              Besides, the complexity of a language is never a primary concern.

                                                                                              I disagree. I think implementation matters.

                                                                                          2. 2

                                                                                            That’s an intersting observation; thanks for sharing it.

                                                                                            they just aren’t exposed to the end developer

                                                                                            I think this supports my point better than I’m able to. Language design is just as much about what is hidden from developers as what is exposed. That generics are hidden from end users is something I greatly appreciate about Go. So when I refer to generics, I’m referring to generics used by every day developers.

                                                                                            I’d be curious what your thoughts on why this discrepancy is OK and why it shouldn’t be fixed by adding generics to the language.

                                                                                            In my opinion the greatest signal that Go doesn’t need generics is the wonderfully immense corpus of code we have from the last decade – all written without generics. Much of it written with delight by developers who chose Go over other langauges for it’s pleasant simplicity and dearth of features.

                                                                                            That is not to say that some of us offasionally could have written less code if generics were available. Particularly developers writing library or framework code that would be used by other developers. Those developers absolutely would have been aided by generics. They would have written less code; their projects may have cost less to initially develop. But for every library/framework developer there are five, ten, twenty (I can’t pretend to know) end user application developers who never had the cognitive load of genericized types foisted on them. And I think that is an advantage worth forgoing generics. I don’t think I’m particularly smart. Generics make code less readable to me. They impose immense cognitive load when you’re a new developer to a project. I think there are a lot of people like me. After years of Java and Scala development, Go to me is an absolute delight with its absence of generics.

                                                                                            1. 6

                                                                                              In my opinion the greatest signal that Go doesn’t need generics is the wonderfully immense corpus of code we have from the last decade

                                                                                              I don’t have a ready example, but I’ve read that the standard library itself conspicuously jumped through hoops because of the lack of generics. I see it as a very strong sign (that’s an understatement) that the language has a dire, pervasive, need for generics. Worse, it could have been noticed even before the language went public.

                                                                                              If you had the misfortune of working with bright incompetent architects astronauts who used generics as an opportunity to make an overly generic behemoth “just in case” instead of solving the real problem they had in front of them, well… sorry. Yet, I would hesitate to accuse the language’s semantics for the failings of its community.

                                                                                          3. 7

                                                                                            I don’t remember exact details, it was super long ago, but I once wanted to write an editor centered around using a nontrivial data structure (“table chain” or “string table” or whatever was the name). Also the editor had some display aspect structures (~cells of terminal). At some point I needed to be able to experiment with rapidly changing the type of the object stored both in the “cells” and “chains” of the editor (e.g. to see if adding styles etc. per character might make sense from architectural point of view). If you squint, those are both kind of “containers” for characters (haskeller would maybe say monads? dunno). I had to basically either manually change all the places where the original “character” type was used, or fall back to interface{} losing all benefits of static typing that I really needed. Notably this was long before type aliases which would have possibly allowed me to push a bit further, though it’s hard for me to recall now. But the pain and impossibility of rapid prototyping at this point was so big I didn’t see it possible to continue working on the project and abandoned it. Not sure if immediately then or some time later I realized that this is the rare moment where generics would be valuable in letting me explore designs I cannot realistically explore now.

                                                                                            In other words, what others say: nontrivial/special-purpose “containers”. You don’t need them until you do.

                                                                                            Until then I fully subscribed to “don’t need generics in Go” view. Since then I’m in “don’t need generics in Go; except when do”. And I had one more hobby project afterwards that I abandoned for exactly the same reason.

                                                                                            And I am fearful and do lament that once they are introduced, we’ll probably see everyone around abusing them for a lot of unnecessary purposes, and that this will be a major change to the taste of the language. That makes me respect the fact that the Team are taking their time. But I do miss them since, and if the Team grudgingly accepts the current draft as passabke, this is such a high bar that it makes me extremely excited for what’s to come, that it will be one of the best ways how this compromise can be introduced. Given that most decisions in languages are some compromises.

                                                                                            1. 6

                                                                                              Yeah, Go is very much not a language for rapid prototyping. It expects you to come to the table with a design already in mind.

                                                                                              1. 2

                                                                                                Umm, what? Honestly not sure if you’re meaning this or being sarcastic (and if yes, don’t see the point). I prototyped quite a lot of things in Go no problem. I actually hold it as one of the preferred languages for rapid prototyping if I expect I might want to keep the result.

                                                                                                1. 5

                                                                                                  I’m being totally serious. Go is chock full of stuff that makes typical rapid prototyping extremely difficult. A lack of a REPL. Compiler errors on unused variables. Verbose error handling. And so on. All of these things combine to make it harder to “design on the fly”, so to speak, which is what rapid prototyping frequently means.

                                                                                                  With that said, Go works great for prototyping in the “tracer bullet” methodology. That’s where your prototype is a complete and production quality thing, and the iteration happens at a higher level.

                                                                                                  1. 1

                                                                                                    Got it, thanks! This made me realize that I reach for different languages in different cases for prototyping. Not yet really sure why now. But I feel that sometimes the dynamic types of Lua make me explore faster, whereas sometimes static types of Go or Nim make me explore faster.

                                                                                            2. 4

                                                                                              I’m going to assume you’re arguing in good faith here, but as a lurker on the go-nuts mailing list, I’ve seen too many people say “I don’t think generics are necessary” or “I haven’t heard a good enough reason for the complexity of generics”. It’s worth pointing out the Go team has collected feedback. Ian Lance Taylor (one of the current proposal’s main authors) spends a large portion of time responding to emails/questions/objections.

                                                                                              I read a comment from someone who was on the Kubernetes team that part of the complexity of the API (my understanding is they have a pseudo-type system inside) is based on the fact that proto-Kubernetes was written in Java and the differences between the type systems compounded with a lack of generics created lots of complexity. (NOTE I don’t remember who said this, and I am just some rando on the net, but that sounds like a decent example of the argument for generics. Yes, you can redesign everything to be more idiomatic, but sometimes there is a compelling need to do things like transfer a code base to a different language)

                                                                                              1. 1

                                                                                                Ouch, I was wondering why the Kubernetes API looks so painfully like Java and not like Go. TIL that’s because it was literally a dumb translation from Java. :/ As much as I’m a pro-generics-in-Go guy, I’m afraid that’s a bad case for an argument, as I strongly believe it is a really awful and unidiomatic API from Go perspective. Thus I by default suspect that if its authors had generics at their disposal, they’d still write it Java-style and not Go-style, and probably still complain that Go generics are different from Java generics (and generally that Go is not Java).

                                                                                              2. 3

                                                                                                I don’t know if the author’s example was a good one to demonstrate the value of generics, but a cursory look at the diff would suggest he didn’t really gain anything from it. I always thought a huge benefit of generics was it saved you 10s or even 100s of lines of code because you could write one generic function and have it work for multiple types. He ended up adding lines. Granted, the author said it was mostly from tests, but still there doesn’t seem to be any dramatic savings here.

                                                                                                1. 3

                                                                                                  I recommend taking more than a cursory look. The value here is very much in the new library interface. In effect, the package provides generalize channels, and before the change, that generalization meant both a complicated interface, and losing compiler-enforced type safety.

                                                                                              1. 2

                                                                                                Why can’t statically linked Go programs look up hostnames? Is it because of how security is set up on OpenBSD?

                                                                                                1. 10

                                                                                                  In general, full support for looking up hostnames requires calling the platform’s C library functions. Go currently only does this in dynamically linked programs; in statically linked programs it uses a pure Go resolver that supports only a subset of the possible hostname lookup features.

                                                                                                  (I’m the author of the linked-to article.)

                                                                                                  1. 5

                                                                                                    Not sure about OpenBSD specifically, but on a lot of *NIX systems name lookup is handled via NSS, which dynamically loads libraries for libc to use: this allows you to extend name lookup without recompiling. Solaris also uses library loading to be able to get locale support in libc.

                                                                                                    It’s interesting that this doesn’t mention macOS. All Go programs on macOS broke a while ago because the syscall parameters for gettimeofday changed and Go didn’t go via libSystem and so didn’t pick up the change.

                                                                                                  1. 7

                                                                                                    This sounds like a great improvement. When I profiled my little web server algernon, os.Stat was one of the slowest functions.

                                                                                                    I wonder when and why in the history of UNIX it was decided to bundle so much information about files into one system call, and if having separate system calls per type of file information returned by stat would give better performance.

                                                                                                    1. 7

                                                                                                      I wonder when and why in the history of UNIX it was decided to bundle so much information about files into one system call, and if having separate system calls per type of file information returned by stat would give better performance.

                                                                                                      I assume this is because all the metadata that stat() returns (inode, mode, UID, GID, size) is stored in a single block; I bet that in traditional UNIX systems this was just the stat_t struct written to disk and reading just the UID wasn’t (and probably still isn’t) really all that faster than just reading everything. I assume that modern filesystems kept this, while also adding their own metadata extensions.

                                                                                                    1. 1

                                                                                                      I just tried it and it didn’t work here. I got:

                                                                                                      error: unknown command: -E
                                                                                                      

                                                                                                      I ran CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -target x86_64-linux" CXX="zig c++ -target x86_64-linux" using zig 0.7.1 and go 1.15.7 on Arch Linux. This is the contents of main.go:

                                                                                                      package main
                                                                                                      
                                                                                                      // #include <stdio.h> // for printf
                                                                                                      // #include <stdlib.h> // for free
                                                                                                      // static void myprint(char *fmt, char* s) {
                                                                                                      //   printf(fmt, s);
                                                                                                      // }
                                                                                                      import "C"
                                                                                                      
                                                                                                      import (
                                                                                                      	"fmt"
                                                                                                      	"unsafe"
                                                                                                      )
                                                                                                      
                                                                                                      func main() {
                                                                                                      	fmt.Print("Hello ")
                                                                                                      	cstrFormat := C.CString("%s\n")
                                                                                                      	defer C.free(unsafe.Pointer(cstrFormat))
                                                                                                      	cstrArg := C.CString("Crustaceans")
                                                                                                      	defer C.free(unsafe.Pointer(cstrArg))
                                                                                                      	C.myprint(cstrFormat, cstrArg)
                                                                                                      }
                                                                                                      

                                                                                                      It works when building with go build.

                                                                                                      1. 2

                                                                                                        You need to follow the steps as described in the blog post. Until Go 1.17 is out you will need to wrap the Zig invocation in a bash script.

                                                                                                        1. 1

                                                                                                          I tried that as well, and it did not work either.

                                                                                                          When creating the two wrapper scripts zcc and zxx and running CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zcc" CXX="zxx" go build --tags extended I get:

                                                                                                          cgo: exec /missing-cc: fork/exec /missing-cc: no such file or directory
                                                                                                          

                                                                                                          When adding $PWD and running:

                                                                                                          CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="$PWD/zcc" CXX="$PWD/zxx" go build --tags extended
                                                                                                          

                                                                                                          it just freezes and nothing happens.

                                                                                                          Edit: The second command with $PWD works if I wait long enough! The only output is:

                                                                                                          warning: unsupported linker arg: --compress-debug-sections=zlib-gnu
                                                                                                          

                                                                                                          But it produces a working executable. Excellent!

                                                                                                          1. 3

                                                                                                            Good job! LLVM is not the fastest compiler out there :) In the blog post I mentioned that compiling Hugo with C extensions takes 4 mins. Without the extensions, it takes like 20 seconds.

                                                                                                            We’re working on adding support for more flags as people use the feature and report issues, in any case those are just warnings that don’t impact the final executable.

                                                                                                            1. 1

                                                                                                              Thanks for the excellent blog post! I dream of one day combining Go and Zig seamlessly, so that Zig can do the performance-critical parts and Go can handle the network-related parts.

                                                                                                      1. 14

                                                                                                        I’ve been really tempted to buy a remarkable2. But the reviews I see say it’s great for note taking but not so great for just reading PDFs. Mostly I want to read PDFs. I’m still on the fence.

                                                                                                        1. 14

                                                                                                          As long as your PDFs don’t require color, it is 100% worth it. Definitely one of my favorite devices at the moment.

                                                                                                          1. 5

                                                                                                            Same. In the month or so I’ve had one, it hasn’t caused me a single frustration (and I’m the kind of person who gets annoyed at the user interfaces of my own Apple products). It works exactly as advertised. Anyone who thinks it might be worth the price tag should watch a third party review video and check out the official and awesome list projects. It has been awhile since I’ve stayed this excited about a new device so long after buying it.

                                                                                                          2. 12

                                                                                                            I picked one up recently hoping that I could migrate a lot of my ebooks and pdfs to it. I don’t plan on returning it, but I wouldn’t recommend it.

                                                                                                            I was a huge fan of the kindle dx, but I’ve managed to break the buttons on a couple which renders them practically useless. I was on the fence with the first remarkable device but figured I’d given the latest iteration a shot. I figured it’d be a good DX substitute. It’s not. I want to like it, the physical design is really good, but the software sucks.

                                                                                                            I have a large collection of documents (epub/pdfs) that I was looking forward to getting on the device. Largely a mix of books published in electronic formats from regular publishers (O’Reilly, Manning, PragProg, etc.) as well as a few papers and docs I’ve picked up here and there.

                                                                                                            First, the reMarkable desktop/mobile app that you have to rely on for syncing is a little wonky. Syncing between the device and mobile/desktop versions of the app works, but leaves a little to be desired. Second, I have yet to load a pdf or epub that isn’t brutally slow to navigate (just page by page). If the document has images or graphics (even simple charts and illustrations) it will affect navigation performance. Occasionally a document will load relatively quickly, and navigate reasonable well, only to slow down after a few page turns. Epubs tend to be a little more difficult to work with - particularly if you decide to change the font. All I have to compare this device to is my broken DX, which, everything considered, positively smokes the reMarkable.

                                                                                                            It’s usable. It works alright for PDFs, less so for epubs. On the positive side, the battery life is quite good.

                                                                                                            1. 3

                                                                                                              I agree with your analysis in most regards. Syncing a lot of ebooks and pdfs to it is not something at which it would excel by default. I have a large Calibre library, and I haven’t synced it over for that reason. However, it’s something I’m looking forward to investigating with KOReader, which supports the reMarkable.

                                                                                                              I haven’t experienced the lag that you talk about, but can understand that that would be bothersome – though I definitely have experienced the “wonkiness” of the companion apps.

                                                                                                              1. 1

                                                                                                                My understanding is that epubs are converted to PDF before being synced? Is that actually the case?

                                                                                                                1. 4

                                                                                                                  It renders the epub to pdf for display but that’s all in-memory. It’s still an epub on disk.

                                                                                                                  1. 1

                                                                                                                    I don’t know. I’ve got a couple books that are both pdf and ePub, and the pdf version behaves a little better. You can also resize and change fonts for ePub doc, but not for PDFs.

                                                                                                                    1. 1

                                                                                                                      Along these lines, another interesting observation I’ve made has to do with the way some kinds of text get rendered. In particular, I’ve encountered epubs with code listings that render fine in other apps and on other devices, but render horribly on the remarkable2 device. Interestingly, in some of those cases I will also have a publisher provided PDF that renders just fine.

                                                                                                                      Further, epubs and PDFs are categorized differently in both the app and the device. With epubs you can change the justification, page margins, line spacing, fonts, and font size. With PDFs you have fewer options, but you do have the ability to adjust the view (which is great for papers since you can get rid of the margins).

                                                                                                                    2. 2

                                                                                                                      I don’t think so – from my playing around with ssh, there are definitely some epubs stored on device. I actually think the browser extension generates epubs, rather than pdfs which was surprising.

                                                                                                                      1. 2

                                                                                                                        Huh. Cool. Hmmm. The real reason I shouldn’t get one is that I always fall asleep with my e-reader and it often bounces off my face.

                                                                                                                        1. 3

                                                                                                                          That’s a pro, for the device, it weighs next to nothing. I’ve damn near knocked myself out dropping an iPad Pro on my head when reading in bed.

                                                                                                                          1. 1

                                                                                                                            For me, it’s more the fact that the Kobo then ends up falling onto the floor. I’m not crazy with that with a $120 device, so …

                                                                                                                  2. 7

                                                                                                                    I own Gen 1 and Gen 2. I love the simplicity and focus of the device. It’s an amazing… whiteboard.

                                                                                                                    Note taking is not suuuper great. Turns out marking up a PDF to take notes actually isn’t that great because the notes quickly get lost in the PDF. It’s not like in real life, where you can put a sticky note to jump to that page. The writing experience is fantastic though. I have notebooks where I draw diagrams/ideas out. I like it for whiteboarding type stuff.

                                                                                                                    Reading is terrible. I mean, it works. Searching is painfully slow. The table of contents doesn’t always show up (even though my laptop PDF reader can read the TOC just fine). When you do get a TOC, the subsections are flattened to the top level, so it’s hard to skim the TOC. PDF links don’t work. Text is often tiny, though you can zoom in. EPUBs appear to get converted to PDFs on the fly and their EPUB to PDF conversion sucks. Though, I’ve found doing the conversion myself in Calibre is way better.

                                                                                                                    Overall, I like the device for whiteboarding. But it’s kinda hard to recommend.

                                                                                                                    1. 2

                                                                                                                      Marking up PDFs works better in color, since you can pick a contrasting ink color. I do it in Notability on my iPad Pro (which is also great for whiteboarding / sketching.)

                                                                                                                      I was tempted by reMarkable when the first version came out, but I couldn’t see spending that kind of money on something that only does note taking and reading. I’m glad it’s found an audience though, it’s a cool device.

                                                                                                                      1. 1

                                                                                                                        Turns out marking up a PDF to take notes actually isn’t that great because the notes quickly get lost in the PDF. It’s not like in real life, where you can put a sticky note to jump to that page.

                                                                                                                        So far the best experience I’ve seen for this is LiquidText on an iPad Pro. While you can write on the PDF as any other annotator, there’s also a lot of more hypertext type of features, like collecting groups of notes in an index, or writing separate pages of notes that are bidirectionally hyperlinked to parts of the document they refer to. Or do things like pull out a figure from a paper into a sidebar where you attach notes to it.

                                                                                                                        The main downside for me is that you do more or less have to go all-on on LiquidText. It supports exporting a workspace to flat PDFs, but if you used the hypertext features in any significant way, the exported PDFs can be very confusing with the lack of expected context.

                                                                                                                        1. 1

                                                                                                                          Agreed that it is hard to find notes. There should be a way to jump to pages that have notes on them (this is how Drawboard PDF works, for example).

                                                                                                                          1. 1

                                                                                                                            What is the advantage over drawing on a piece of paper or on a whiteboard, then taking a photo of what you’ve drawn, if needed?

                                                                                                                            1. 1

                                                                                                                              I tried paper note books, but I’m too messy and make too many mistakes. Erasing, moving, and reordering is hard on paper.

                                                                                                                              A whiteboard is pretty good for temporary stuff and erases better than paper. But, it can be a bit messy.

                                                                                                                              I also tried Rocketbook for a while. I got the non-microwaveable (yes you read that right) one. That was okay. A little meh for me.

                                                                                                                              And of course, you can’t read PDFs on any of these.

                                                                                                                        1. 2

                                                                                                                          I’m dreaming of Zig, but with operator overloading to make implementing mathematical expressions bearable. Anyone have experience with Odin?

                                                                                                                          1. 2

                                                                                                                            I would take Julia’s style of multi dispatching. I’d also be happy with Vector / Matrix / Tensor data types built in.

                                                                                                                          1. 7

                                                                                                                            This mistake of the X11 architecture can never, ever be fixed. X11 is too old, too ossified, and has too many quagmire-trapped stakeholders to ever make any meaningful changes to it again. That’s why people keep trying to replace X11 – and failing, because it’s too entrenched.

                                                                                                                            Meanwhile, Sway, Wayland and Swaylock are doing fine, and have been doing fine for years.

                                                                                                                            Android too.

                                                                                                                            Both X and XScreensaver are replaceable.

                                                                                                                            1. 18

                                                                                                                              Well, with Sway having the very same issues.

                                                                                                                              1. 3

                                                                                                                                That is disconcerting! And I have never seen this problem. But I still think both X and XScreensaver are replaceable.

                                                                                                                                The author of XScreensaver obviously have other good points, though.

                                                                                                                                1. 2

                                                                                                                                  GNOME is probably in the best position to handle this – with everything being integrated in the gnome-shell process, the whole class of interprocess issues (like “lock process crashes”) is gone. If the lock crashes, it takes the whole desktop session with it :)

                                                                                                                                  But yeah, it should be quite easy to make the wlroots world more reliable against lock crashes. In addition to input-inhibit, we could have a “hardcore mode” protocol where the compositor would e.g. not present any other windows until it gets an actual positive confirmation from the lockscreen, and restarts it if it crashes.

                                                                                                                                  Thing is, most people don’t care enough about screen locking security these days. It’s mostly a casual deterrent against kids/parents/coworkers/whatever. Most modern threats don’t have physical access at all.

                                                                                                                                  1. 5

                                                                                                                                    Most modern threats don’t have physical access at all.

                                                                                                                                    FWIW, I know of a place where people with Linux workstations are explicitly required to log out of their sessions when leaving their desks, rather than lock their screens, specifically because it’s notoriously finicky and because not everyone who is in an office is guaranteed to be a coworker, or a coworker with good intentions.

                                                                                                                                    Maybe most modern threats don’t have physical access at all but that doesn’t stop old-school threats like “somebody copies data off of someone’s computer” from working quite reliably.

                                                                                                                              2. 5

                                                                                                                                Meanwhile, Sway, Wayland and Swaylock are doing fine, and have been doing fine for years.

                                                                                                                                The original argument (that jwz repeats in this post) predates Wayland by about five years, and actually translates quite well to Wayland, too. The Wayland equivalent of this bug – a screen locker that does not fail safely – is just as bad.

                                                                                                                                (Edit: granted, the big and very relevant deal about X11 is that it does make writing a locker that fails safely really, really hard. Hell, it makes it obnoxiously hard to write a locker in the first place, without even thinking about how it might fail. My point is definitely not that you’re wrong, IMHO you are absolutely right, just that the post ought to be read in a slightly different key – it’s about a debate, and an argument, that predate the first useful Wayland compositors for desktops by 10+ years)

                                                                                                                              1. 3

                                                                                                                                This is well made.The web page gives a nice overview, and is easy to search. I see that Jakub Klinkovský stands behind many of the commits to archmanweb. Nicely done!

                                                                                                                                1. 49

                                                                                                                                  Good lord, how is it elegant to need to turn your code inside-out to accomplish the basic error handling available in pretty much every other comparable language from the last two decades? So much of Go is well-marketed Stockholm Syndrome.

                                                                                                                                  1. 16

                                                                                                                                    I don’t think that responding with a 404 if there are no rows in the database is that any language supports out of the box. Some frameworks do, and they all have code similar to this for it.

                                                                                                                                    1. 3

                                                                                                                                      And sadly so often error handling is often done in a poor manner in the name of abstraction, though really bad one that effectively boils down to ignore that things can go wrong, meaning that one ends up digging through many layers when they actually do go wrong.

                                                                                                                                      People eventually give up and copy paste StackOverflow[1] solutions in the hopes that one of them will work, even when the fix is more accidental and doesn’t fix the root cause.

                                                                                                                                      The pinnacle was once checking code that supposedly could not fail. The reason was that every statement was wrapped in a try with an empty catch.

                                                                                                                                      But back to the topic. Out of the box is all good and nice until you want to do something different which in my experience happens more often than one would think. People sometimes create workarounds. In the example of non existing rows, for example doing a count before fetch, so doing two queries instead of one, just to avoid cases where a no rows error would otherwise be thrown.

                                                                                                                                      Now i am certainly not against (good) abstractions or automation, but seeing people fighting against those in many instances makes me prefer systems where they can be easily be added and can easily be reasoned about, like in this example.

                                                                                                                                      [1] Nothing against StackOverflow, just blindly copy pasting things, one doesn’t even bother to understand.

                                                                                                                                    2. 10

                                                                                                                                      In what way is Go’s error handling turning my code inside out?

                                                                                                                                      1. 6

                                                                                                                                        Pike has set PLT back at least a decade or two.

                                                                                                                                        1. 7

                                                                                                                                          It is possible to improve the state of the art while also having a language like Go that is practical, compiles unusually fast and is designed specifically to solve what Google found problematic with their larger C++ projects.

                                                                                                                                          1. 8

                                                                                                                                            compiles unusually fast

                                                                                                                                            There is nothing unusual about it. It’s only C++ and Rust that are slow to compile. Pascal, OCaml, Zig and the upcoming Jai are decent. It’s not that Go is incredible, it’s that C++ is really terrible in this regard (not a single, but a lot of different language design decisions made it this way).

                                                                                                                                            1. 3

                                                                                                                                              For single files, I agree. But outright disallowing unused dependencies, and designing the language so that it can be parsed in a single pass, really helps for larger projects. I agree on Zig and maybe Pascal too, but in my experience, OCaml projects can be slow to compile.

                                                                                                                                              1. 2

                                                                                                                                                I’m enjoying tinkering with Zig but I do wonder how compile times will change as people do more and more sophisticated things with comptime.

                                                                                                                                                1. 2

                                                                                                                                                  My impression from hanging out in #zig is that the stage 1 compiler is known to be slow and inefficient, and is intended as a stepping-stone to the stage 2 compiler, which is shaping up to be a lot faster and more efficient.

                                                                                                                                                  Also there’s the in-place binary patching that would allow for very fast incremental debug builds, if it pans out.

                                                                                                                                              2. 2

                                                                                                                                                Don’t forget D.

                                                                                                                                              3. 1

                                                                                                                                                My experience with Go is that it’s actually very slow to compile. A whole project clean build might be unusually fast, but it’s not so fast that the build takes an insignificant amount of time; it’s just better than many other languages. An incremental build, however, is slower than in most other languages I use; my C++ and C build/run/modify cycle is usually significantly faster than in Go, because its incremental builds are less precise.

                                                                                                                                                In Go, incremental builds are on the package level, not the source level. A package is recompiled when either a file in the same package changes, or when a package it depends on changes. This means, most of the time, that even small changes require recompiling quite a lot of code. Contrast with C, where most of the time I’m working on just a single source file, where a recompile means compiling a single file and re-linking.

                                                                                                                                                C’s compilation model is pretty bad and often results in unnecessary work, especially as it’s used in C++, but it means that you can just work on an implementation by just recompiling a single file every build.

                                                                                                                                                1. 1

                                                                                                                                                  I have not encountered many packages that take more than one second to compile. And the Go compiler typically parallelizes compilation at the package level, further improving things. I’m curious to see any counter examples, if you have them.

                                                                                                                                              4. 4

                                                                                                                                                I don’t remember anyone in POPL publishing a PLT ordering, partial or total. Could you show me according to what PLT has been set back a decade?

                                                                                                                                              5. -2

                                                                                                                                                Srsly, I was looking for simpler, and was disappointed by the false promise.

                                                                                                                                              1. 30
                                                                                                                                                • RISC-V CPUs. Because open standards encourage co-operation across borders.
                                                                                                                                                • Zig. Because people want to replace C with something more secure, but in a gradual process, and Zig includes a C compiler.
                                                                                                                                                • MIDI over Bluetooth 4. Because it’s handy.
                                                                                                                                                • The Gemini protocol, since retrominimalism is still fun.
                                                                                                                                                • Godot for game development, because it has matured enough.
                                                                                                                                                • TOML since it seems to be the least disliked configuration format.
                                                                                                                                                1. 5

                                                                                                                                                  Godot is in a great spot and just keeps getting better. I’m hoping you’re right on this one!

                                                                                                                                                  1. 2

                                                                                                                                                    MIDI over Bluetooth 4. Because it’s handy.

                                                                                                                                                    Had to look that up. Latency jitters between 3-10ms. Figures.

                                                                                                                                                    1. 1

                                                                                                                                                      3-10 ms is acceptable latency for MIDI though?

                                                                                                                                                      1. 4

                                                                                                                                                        Drummers will disagree.

                                                                                                                                                        But even then, It isn’t just 3-10ms latency; It is the latency from bluetooth + whatever other latency in the latency chain.

                                                                                                                                                        It all adds up.

                                                                                                                                                        1. 5

                                                                                                                                                          (Am drummer) A total latency, i.e. of the whole chain, of 3-10 ms is okay. 3-10 ms for a single MIDI message is 3-10 times more than one would expect :-). Also, jitter matters enormously. A constant latency of 20 ms is annoying, but you can sort of live with it if you really try. Constantly jittering between 5 and 20 ms, on the other hand, feels like you’ve had one too many drinks.

                                                                                                                                                    2. 2

                                                                                                                                                      “…encourage co-operation across borders” well said! I actually never considered geopolitical impact with processors. could you point me towards some reading, or share insight?

                                                                                                                                                      1. 2

                                                                                                                                                        I’m not an expert on RISC-V, but I know that both MIT and China work on improving it. There’s also political will in Europe to build a European CPU.