Live data from Hacker News

Wc in D: 712 Characters Without a Single Branch

dlang.org

71–80 of 89 posts

Re: Wc in D: 712 Characters Without a Single Branch

#71
post #17

I find D easier to grok coming from a Java/Python background.

I've only toyed with D a bit. IMHO, if you come from a typical OO programming language background (which to me includes C++, Java, Python...), the majority of D will immediately feel familiar, and to a great extent, obvious. The syntax is familiar and the ideas are familiar. You don't have to learn anything new (not immediately anyway) like you do in Rust (where you basically need to learn EVERYTHING new). Where this…

> they claim that you can run D without a GC (the new), but apparently a good chunk of the stdlib requires the GC (the old), so you're stuck.

The intent isn't to turn off the GC completely (though GC-averse folks assume that it is). The `@nogc` function attribute is intended to be applied where you need it. Then you can guarantee that in that function's call stack, no language features that require the GC will be used.

The standard library has been retrofitted to eliminate use of the GC where it isn't needed and provide alternatives where possible (such as a function that takes a buffer as an argument alongside one that allocates). There may still be places where it can be trimmed down even more, but it will never be fully `@nogc` compatible.

D is meant to be used with the GC, but provides the means to avoid allocations, turn collections on/off (`GC.disable/enable`) and command line options for profiling GC usage and affecting its behavior. Anyone who wants to turn off the GC completely is going beyond the primary intended use case and is of course going to run into bumps with the standard library. Much of it is still usable, though.

See https://dlang.org/blog/the-gc-series/

Re: Wc in D: 712 Characters Without a Single Branch

#72

Earlier quoted context omitted.

"Counting newlines" implies branching.

Not really: cnt += *ptr++ == '\n' Should compile down to no branches (not even cmov) by summing the value of the flag register directly. Would be a it hard to stop without taking a branch though. Would you consider function pointer calls a branch? If that's too easy, what about taking a segfault?

Even if you do the branchiest thing possible in the source, no bitwise or "looks cmov-y" stuff, all compilers that matter will do this without a branch with optimization on:

https://godbolt.org/z/XCBGYW

Only icc vectorizes this at -O2 (still branchless, of course), but clang and gcc vectorize it if you go to -O3.

Re: Wc in D: 712 Characters Without a Single Branch

#73
post #57
post #47

I believe I'm missing something here or my day was too long, but in Clojure this can be squeezed in 13 lines and 435 characters keeping things fairly readable (for Clojure & Lisp developers ;)). (defn wc [^String file] (with-open [rdr (clojure.java.io/reader file)] (apply (partial printf "%d %d %d\n") (reduce (fn [[nl nw nb] ^String ln] (let [words (count (.split ln "[ ]+")) bytes (alength (.getBytes ln "UTF-8"))] [(…

Neat! I wonder if the character decoding & regex usage has noticeable performance impact. My Common Lisp version was sped up somewhat by switching from a character stream to a byte stream: https://git.tazj.in/tree/fun/wcl/wc.lisp You can try this one via Nix with: nix-build -E '(import (builtins.fetchGit "https://git.tazj.in") {}).fun.wcl'

That's a very impressive Nix configuration. Nicely done!

Re: Wc in D: 712 Characters Without a Single Branch

#74

Earlier quoted context omitted.

Not really: cnt += *ptr++ == '\n' Should compile down to no branches (not even cmov) by summing the value of the flag register directly. Would be a it hard to stop without taking a branch though. Would you consider function pointer calls a branch? If that's too easy, what about taking a segfault?

Even if you do the branchiest thing possible in the source, no bitwise or "looks cmov-y" stuff, all compilers that matter will do this without a branch with optimization on: https://godbolt.org/z/XCBGYW Only icc vectorizes this at -O2 (still branchless, of course), but clang and gcc vectorize it if you go to -O3.

Sure, but where's the code golfing fun in there ;)

Re: Wc in D: 712 Characters Without a Single Branch

#75
post #68
post #65

Earlier quoted context omitted.

It's been a while since I last wrote CL but I think your program can produce any counts between zero and the correct one – you need to use eql instead of eq if you want this to work in standard common lisp.

Ah, you're right of course - fixed. Though that still won't make this portable, as I'm using an SBCL-specific way of accessing argv.

`unix-opts` is in available in quicklisp -- it's small, and has a portable `argv` wrapper function.

Re: Wc in D: 712 Characters Without a Single Branch

#76

Earlier quoted context omitted.

Even if you do the branchiest thing possible in the source, no bitwise or "looks cmov-y" stuff, all compilers that matter will do this without a branch with optimization on: https://godbolt.org/z/XCBGYW Only icc vectorizes this at -O2 (still branchless, of course), but clang and gcc vectorize it if you go to -O3.

Sure, but where's the code golfing fun in there ;)

:) I guess I'm not fun at [code golfing] parties.

I just want to gently push back on the notion that the source level branchy-ness is tightly tied to the generated assembly level branchiness.

Sometimes, it is - but it is a long topic to characterize when. For simple things like counters based on a condition, you'll almost always get branch-free. Same for assignment/return value based on a condition, where the possibilities don't involve lots of asymmetric work (or a asymmetric memory access).

Re: Wc in D: 712 Characters Without a Single Branch

#77
post #23

Gave myself a quick D lesson just to understand the approach to flags here (Yes.keepTerminator rather than just a meaningless bool). Turns out D lets you define a template with any args you like, in this case taking a string for a name of a Flag type, which in turn contains an enum with 'yes' and 'no' boolean values. This means that you can only use the right type of Flag, with a matching name, and its yes/no value.…

Spot on! :) With the help of opDispatch (the catch-all member function temlate), it's possible to drop the string from the use site. (I don't know a way of dropping it from the type name.) import std.stdio; import std.typecons; import std.string; // This type's opDispatch removes the need for string in the flag name. struct FlagFromBool { auto opDispatch(string flagName)(bool value) { mixin (format!q{ return value ?…

Both your convenience function and the quotes in the type name can be removed via the use of static opDispatch:

struct FlagImpl(string name) { bool value; alias value this; }

struct Flag { alias opDispatch(string name) = FlagImpl!name; }

struct Yes { static auto opDispatch(string name)() { return FlagImpl!name(true); } }

struct No { static auto opDispatch(string name)() { return FlagImpl!name(false); } }

void fun(Flag.foo a) {} // Look ma, no quotes!

unittest { fun(Yes.foo); fun(Flag.foo(true)); }

Re: Wc in D: 712 Characters Without a Single Branch

#78
post #68

Earlier quoted context omitted.

Ah, you're right of course - fixed. Though that still won't make this portable, as I'm using an SBCL-specific way of accessing argv.

`unix-opts` is in available in quicklisp -- it's small, and has a portable `argv` wrapper function.

Thanks for the tip, added that: https://git.tazj.in/commit/?id=10e2e56b67b41eb6315fdc4cc1bc1...

Re: Wc in D: 712 Characters Without a Single Branch

#79
post #51

This is ridiculous: of course there are branches, but you don’t explicitly write them. This is purely aesthetic. Edit: i simply wish the author illustrated why this is good or desirable—conditionals are not difficult to read.

The aesthetic aspect is insignificant, it's about the semantics -- and thus reasoning about the code and other such properties. So nothing ridiculous about it. It's like Haskell code "of course has" anything C has, as underneath the both run assembly instructions full of gotos and state manipulation, you just "don't explicitly write it".

[deleted]

Re: Wc in D: 712 Characters Without a Single Branch

#80
post #51

This is ridiculous: of course there are branches, but you don’t explicitly write them. This is purely aesthetic. Edit: i simply wish the author illustrated why this is good or desirable—conditionals are not difficult to read.

The aesthetic aspect is insignificant, it's about the semantics -- and thus reasoning about the code and other such properties. So nothing ridiculous about it. It's like Haskell code "of course has" anything C has, as underneath the both run assembly instructions full of gotos and state manipulation, you just "don't explicitly write it".

Do you have difficulty reasoning through conditionals?

Meanwhile the semantics of objects, especially one named “Output”, are super obvious and easy to reason about.

Post reply on HN