HNHacker News
TopNewBestAskShowJobs

gnuvince

2,803 karma · joined March 11, 2010

submissionscomments
gnuvince··on Absolute Beginner's Guide to Emacs (2012)
> M-x ansi-term ask for [...]/emacs/libexec/emacs/26.1/x86_64-w64-mingw32/cmdproxy.exe and then throws "Spawning child process: Invalid argument".

Ah, that's too bad.

gnuvince··on Absolute Beginner's Guide to Emacs (2012)
> * super powerful, easy to use, integrated command and fuzzy file search, also with a good UX.

Sounds like you should try ivy and its companions. Ivy offers fuzzy matching for all operations in Emacs (e.g., switching buffers, opening files, looking up documentation) and the counsel packages (e.g., counsel-rg) use that same interface to interact with external tools such as ripgrep or git grep.

Ivy has completely taken over my Emacs experience, and it did not require a lot of configuration, just a few keybindings.

As for a terminal, I don't have a Windows machine to test, but `M-x ansi-term` is pretty much exactly like a regular terminal: you can run any program in it, including htop or even vim.

gnuvince··on Absolute Beginner's Guide to Emacs (2012)
I find Jon enraging, especially when he whines about Emacs: a number of the things he complains about are either fixed in newer versions of Emacs (he's still on Emacs 23) or packages offer a vastly improved user experience.
gnuvince··on Why is 2 * (i * i) faster than 2 * i * i in Java?
Because of integer overflows and floating-point operations, the notion of equivalent mathematical expressions is tricky.

    fn main() {
        let a: i8 = 125;
        let b: i8 = 3;
        let c: i8 = (a + b) / 2;
        let d: i8 = b + ((a - b) / 2);
        println!("{} {}", c, d);
    }
This program outputs `-64 64` although the computations of `c` and `d` are equivalent.

Here's another example using floating point numbers:

    fn main() {
        let mut total1: f32 = 0.0;
        let mut total2: f32 = 0.0;
        let mut counter1: f32 = 0.0;
        let mut counter2: f32 = 100.0;

        for _ in 0 .. 10001 {
            total1 += counter1;
            total2 += counter2;
            counter1 += 0.01;
            counter2 -= 0.01;
        }
        println!("{} {}", total1, total2);
    }
The output of this program is `500041.16 500012.16`, a difference of 25 for a program that computes the same result (unless I made a mistake).
gnuvince··on Falling in love with Rust
No, he had intrusive pointers; his rectangle nodes were in a couple of doubly-linked lists and an AVL tree at the same time.
gnuvince··on Falling in love with Rust
The naïve Rust part is explained in a video [1] that Bryan released a couple of weeks ago; instead of using bespoke data structures for his problem, he shoved everything into HashMaps and BTreeSets and used numerical indices rather than pointers to "emulate" a doubly-linked list. It turned out that was good enough to beat C.

[1] https://www.youtube.com/watch?v=aWbGPMxs0AM

gnuvince··on Falling in love with Rust
In our continuous integration system at work, I've enabled sccache with the S3 backend. This reduced the compile times from 20-25 minutes (tests and release build) to 8-9 minutes. Still longer than I like, but it's possible to ease the pain somewhat.
gnuvince··on Falling in love with Rust
If you have a blog, that would make for an amazing entry, going from 50% slower to 25% faster.

Edit: HOLY CRAP! I have a program written in Rust, ppbert[1], and I just tried wrapping my StdoutLock object in a BufWriter, and I improved the performance of my pretty-printing by a factor of 2x! I knew to use BufReader for files, I didn't know it was helpful for stdin and stdout! Thank you _so much_ for sharing your experience, I've certainly benefited!

    Benchmark #1: ppbert -2 *.bert2
      Time (mean ± σ):      3.816 s ±  0.115 s    [User: 2.494 s, System: 1.321 s]
      Range (min … max):    3.688 s …  4.028 s

    Benchmark #2: ppbert-dev -2 *.bert2
      Time (mean ± σ):      1.728 s ±  0.045 s    [User: 1.493 s, System: 0.234 s]
      Range (min … max):    1.678 s …  1.843 s

    Summary
      'ppbert-dev -2 *.bert2' ran 2.21x faster than 'ppbert -2 *.bert2'
[1] https://github.com/gnuvince/ppbert
gnuvince··on Falling in love with Rust
Language-wise, Rust is really top-notch, I find it hard to fault any design decision. There are some design choices that annoy me (e.g., two closure types can never be equal), but there is always a fact-based rationale for why things are the way they are.

My two major pain points in Rust are (1) the compile times, (2) the high variance of quality in the ecosystem.

The compiler for Rust is very slow, it takes minutes to build software from scratch. Things are getting better with incremental compilation, but it's definitely not as fast as D or Go to compile, and that can be very grating during development.

Anyone can easily contribute to the crates ecosystem and post their libraries and programs to crates.io. Unfortunately, there is no real way to know what's production-quality and what's a toy. You can try and rely on the number of downloads, the names of the contributors, etc., but there is no system that tells you what other Rustaceans think of a crate. For instance, I tried using an HTTP client with few dependencies (because the most downloaded option, reqwest, has a lot of dependencies), but I found that (a) the library issued a read(2) syscall for each byte that it downloaded, (b) did not always return the full payload for HTTPS. There was no way I could tell from just looking at the crates.io page.

gnuvince··on Go 2 Draft Designs
I got turned off of failure when a reddit user reported that it slowed down his program by 300x and the author of failure's response was that the original poster had misused failure.

https://www.reddit.com/r/rust/comments/7te8si/personal_exper...

gnuvince··on Go 2 Draft Designs
I'm not sure why you would prefer to (1) create a new trait, (2) create a custom derive for that trait, (3) derive that trait for all the types you want to debug over assigning to a variable and printing. It sounds like an over-engineered solution to a non-problem to me.
gnuvince··on Ask HN: What is the most unethical thing you've done as a programmer?
Without going into specifics, can you outline the kind of illegal activities that might appear in a git commit history? I'm guessing copyright infringements mostly?
gnuvince··on Toml: Tom's Obvious, Minimal Language
An array of dictionaries. In JSON, my example becomes:

    {
        "designers": [
            {"name": "Guido", "lang": "Python"},
            {"name": "Larry", "lang": "Perl"}
        ]
    }
gnuvince··on Toml: Tom's Obvious, Minimal Language
To me, there was nothing obvious about the double bracket syntax, e.g.:

    [[designers]]
    name = Guido
    lang = Python

    [[designers]]
    name = Larry
    lang = Perl
gnuvince··on The Awk Programming Language (1988) [pdf]
Agreed. I learned awk a bit late in my Linux journey (started using Linux in 1999, learned awk in 2016), but I can't imagine not using it daily now. Great tool to manipulate data, and it's great for when you want a Unix tool that doesn't exist (e.g., computing the sum or mean of a stream of numbers).
gnuvince··on Show HN: Tube – Minimalist YouTube
I searched for "darkest dungeon" and first hits were for Ed Sheeran and One Direction. I know searching is a tricky problem, but this is ridiculously bad.
gnuvince··on Memory Safety in Rust: A Case Study with C
You have two dialects: Safe Rust and Unsafe Rust. Safe Rust is regular Rust code, the kind of code that you should write 99.9% of the time. Unsafe Rust is a superset of Safe Rust; all of the Safe Rust checks still apply. Within an unsafe block, you gain access to a few extra tools that are not available in Safe Rust: you can dereference raw pointers, you can modify global variables, you can invoke unsafe functions, and a few more.
gnuvince··on Memory Safety in Rust: A Case Study with C
> who the hell gets the address of stack memory and returns it? This is C 101

John Carmack, apparently: https://twitter.com/ID_AA_Carmack/status/587077680652230656

gnuvince··on Practical Unix Manuals: mdoc
The main issue with this is that AsciiDoc cannot express semantics. When writing manpages, you can specify that something is a flag or a function parameter, etc.
gnuvince··on Low Hanging Fruit of Programming Language Design
I mentioned a few months ago in a similar thread that I now actively try to recognize when I'm creating an incomprehensible 300-line "abstraction" in order to avoid copying four line of code.
gnuvince··on Handmade Hero – A complete game live-coded from scratch
> Also he's using emacs.

Not anymore.

gnuvince··on Handmade Hero – A complete game live-coded from scratch
A comment thread from a couple years ago that resonated with me: https://news.ycombinator.com/item?id=11087399

I watched about a dozen Handmade Hero episodes, and I was a bit annoyed that every session resulted in a random hunt to fix a bunch of bugs because there was not sufficient abstraction. It wouldn't be so bad if the abstractions were upcoming, but Casey seems to have an aversion to abstraction and I stopped watching because I grew bored of watching him jumping around in a bunch of files trying to figure out what memory write caused an issue at run-time.

gnuvince··on Why did we choose Rust to develop TiKV?
Traits can be used for polymorphism: https://play.rust-lang.org/?gist=5d4bae81014d879b43bad1326dd...
gnuvince··on JOE – Joe's own editor 4.5 released
mg also has keyboard macros, but it doesn't have UTF-8 support yet, which is the reason why I prefer to use jmacs for quick edits.
gnuvince··on Mrustc: a Rust compiler written in C++
This is akin to suggesting that learning Java could be simplified by making its type system optional. Also, if one could turn off safety features, why would they ever switch them back on? They learned a different language, one where those checks are not present.
gnuvince··on Revisiting Knuth and McIlroy's word count programs (2011)
I used literate programming to write ~25 programs last year, and I found that the coolest thing about the technique was crafting a narrative for understanding the problem and appreciating the solution.

One difficulty when reading somebody else's program is thinking "why didn't he just do X?" and not having a clear answer. In a good literate program—and it's harder to write good literate programs than simple programs—the author can touch on why a particular approach is unsuitable, or why he preferred one valid approach over another valid approach.

In the end, I think I prefer to write "regular code"; tools like editors, debuggers, build systems, etc. work better with real code. Still, I try to write doc-comments that inject better narratives in my programs and, hopefully, help the readers attain a better understanding.

gnuvince··on LLVM 5.0.0 Release
What's a good reference to get started with LLVM? I've been wanting to write an Oberon-2 compiler, but I don't know what LLVM provides, nor how I might use it from Rust.
gnuvince··on Ask HN: Resources for building a programming language?
I've been recommending this to co-workers who want to learn how to write their own language. I had ideas on how I would write a book on compilers and Bob had all the same idea, but he actually went ahead and acted on them.

1. Avoid long discussions on the theory of parsing, how to transform regular expressions into table-driven DFAs, how to build an LR(1) parser, etc.. These topics can be interesting later on, but for the benefit person who just wants to learn to write a language, the author should instead focus how to write the scanner and the parser by hand using a predictive recursive-descent. The value of this approach are three-fold: (1) the book is shorter, (2) it's a simple approach that works with any language without specialized tool (useful if someone wants to write such a tool for vim or Emacs, say), (3) it feels more concrete, more "real" to write a parser by hand rather than create a few grammar rules and let an external tool create the code that does the parsing.

2. "Breadth-first" rather than "depth-first". In a typical compiler textbook, each chapter exhausts almost all that there is to say about a topic before moving on. I think a more practical book will avoid such deep discussions and try to go as quickly as possible from source language to executable program. After the initial implementation is complete, the author can go back and add more details. Bob's approach of having two interpreters, one AST-walker and one that builds bytecode, fits that idea quite well.

3. Multiple implementation languages. The implementation of a language is largely guided by its host language: if using ML or Haskell, then sum types will be quite handy; in Java we can rely on the library's excellent collections. It's cool that Bob decided to write an interpreter in Java and another one in C; the reader will get to see how some decisions in the former (e.g., using exceptions) are "translated" in the later.

4. A full implementation in the book. Many compiler textbooks use pseudo-code and steer clear of "pedestrian" topics like good error handling. By having a full implementation, Bob ensures that the little dirty details are addressed also and not swept under the rug and left for the readers to discover and struggle with.

I really look forward to the day when I can order a copy of Crafting Interpreter, I have no doubt that it will be a terrific book.

gnuvince··on Writing parsers like it is 2017
I tried to use nom for one of my projects, but I found that it had two major problems. First, the macro syntax was hard to use, hard to learn, and hard to debug. Sometimes you had to put an expression in parentheses, even if it seems that it should be unnecessary, so that the macros would be able to parse your code. I also found the macros hard to compose, which is ironic for a parser combinator library.

My other problem was with error handling. I wanted to have my own `Error` enum to represent errors in my program. Nom supports a custom error type, but I now had to write out type annotations in many places with the fish syntax (e.g. foo::<&[u8], Ast, Error>()) and they are quite long annotations. In addition, some of the macros would not work—or at least, I couldn't get them to work—with my custom error type, and I had to revert to using functions in a way that was absolutely not compositional.

In the end, since the format I was parsing was simple and regular (Erlang's External Term Format), I wrote a parser by hand and removed the dependency on nom. The result is as just as fast and produces meaningful error messages. It's actually less tedious, because I am using simple functions that have the syntax and semantics that I already know; maybe if I had a more complex format to parse I would sing a different tune, but for the moment I prefer to avoid using nom.

gnuvince··on An Intro to Compilers
I was T.A. for COMP-520, Compiler Design, at McGill University for two years, and it was the best job I've ever had. The compiler project had not been updated in 10-12 years; my adviser trusted me to make a new, interesting project. I was paid by the department for 5 hours of work per week, but I poured in more than 35 per week to design, document, and implement a subset of Go

My hard work paid off immediately. Students were more interested by a language that was new, modern, and used in the industry than by the previous language that was used, Wig. As a result, enrollment jumped from 12-14 students to 45. Though it was a subset, and much of what makes Go interesting was removed (concurrency, interfaces, GC) it was still an extremely demanding project. Many times I thought that the project was too big, that we needed to cut back, but the students were real troopers and chugged through (by the way, when did 20-year olds become so smart?! I was never this bright when I was their age!) and all teams completed the project and made me very proud.

You can see the page for the first year of the class, along with relevant documents at http://www.cs.mcgill.ca/~cs520/2015/

← PreviousPage 5 of 20Next →