HNHacker News
TopNewBestAskShowJobs

smitherfield

1,770 karma · joined March 26, 2015

submissionscomments
smitherfield··on C++ Core Guidelines
>You can't put runtime assert in constexpr function.

As of C++17 you can: http://en.cppreference.com/w/cpp/error/assert

You can also throw exceptions in constexpr functions since C++14.

smitherfield··on Icelandic language battles threat of 'digital extinction'
Sure, there's more interest in Welsh in recent decades, but I strongly suspect it will resume declining if it hasn't already.

I used Welsh, Irish, Catalan and French-in-Quebec as examples because they're all languages that declined (to varying degrees) over several centuries under (varying degrees of) government suppression, experienced a partial rebound in interest and popularity in the 20th century after government policy was changed to encourage their use, but ultimately returned to the same trend of declining usage, something like

  100|
     N
     |\_
     |  \_
     |    \_          ____
     |      \_      _/    \_
     |        \____/        \
     N_______________________
    0|suppressed   encouraged
smitherfield··on Icelandic language battles threat of 'digital extinction'
“Germany” hasn’t been a country very long, only since 1871, but an identifiable German culture has existed since Roman times. German (or precursors) was spoken in Alsace for well over a millennium before declining and dying out in the 19th and 20th centuries.
smitherfield··on Icelandic language battles threat of 'digital extinction'
But is it a sustainable road? French-Canadians have been complaining for many years that Montreal's "bilingual" neighborhoods become English-speaking in a decade or so, and "French-speaking" neighborhoods become bilingual. And this is despite extensive government efforts to encourage or even enforce the use of French. You can see the same trends in Catalonia, Wales, Ireland, etc.

Where the government intervenes in the opposite direction, the transition can be much more rapid. Visiting Strasbourg (in Alsace, France), people's surnames, street and place names, and the local cuisine are all German, but nobody speaks a word of it. It was amazing (and slightly depressing) to see how in 2-3 generations a city could forget the language it spoke for nigh-on 1,500 years.

The way things are going, I wouldn't be surprised if Dutch were considered a dying language 50 years from now.

smitherfield··on Why writing a linked list in safe Rust is so damned hard
> Eh, I disagree...

The reason transmute is (particularly) unsafe is because it can be quite difficult to tell whether a variable is bound to a value, a (possibly implicitly-dereferenced) reference or a slice, and so, given transmute's implicit type inference, it's very easy to quietly get either the source or destination type very wrong.

The size-checking is also I would argue useless bordering on worse than useless (false sense of security) since any two references or two slices are the same size, but are unlikely to actually be interconvertible, and it also fails to check alignment.

C and C++ (particularly the latter) make it much more difficult to inadvertently cast between values and pointers, and the strict aliasing rules (aliasing almost always illegal except through `char`) are draconian enough to discourage the practice of type-punning-through-indirection (and ensuing alignment bugs) altogether.

`memcpy` (and unions-as-implemented) is nice because it's explicit and it just works.

> I'm curious if you've got a defect report link or similar

I'm having a hard time finding the detailed original paper pointing it out, but see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p059...

smitherfield··on Why writing a linked list in safe Rust is so damned hard
> "what does this language make easy" (C: raw memory manipulation!)

Depending on what you mean by "raw memory manipulation" that can actually be surprisingly difficult with C, without running into undefined behavior, at least technically-speaking. e.g. type-punning through unions is defined by all implementations I can think of, but technically UB according to the standard.

That said, if you know the UB rules, C/C++ are still the "nicest" mainstream languages to use for that sort of super-low-level manipulation of raw object representations. The non-UB type-punning methods in C/C++ (`memcpy(3)`, casting addresses to pointer-to-`char`), finicky as they are, are still more ergonomic and, ironically, safer than Rust's poorly-designed `mem::transmute()` API.

Language-lawyering is quite the rabbit hole, BTW; for example, it was discovered a few years ago that the wording of the formal C++ memory model defined in the C++11 and later standards means all non-trivial C programs (technically-speaking, not according to any existing or sane implementation) invoke undefined behavior in C++. We'll be lucky if the bikeshedding over the fix for this gets resolved in time to make C++20.

  #include <stdlib.h>

  void *safe_ptr(void *p) {
  	if (!p) exit(1);
    	return p;
  }

  #define INIT(TYPE) safe_ptr(malloc(sizeof(TYPE)))

  int *get_intbuffer(void) {
  	enum {N=3};
  	int *const intbuffer = (int*)INIT(int[N]);
  	int i = N;
	/* Technically UB in C++; lifetime starts
	 * w/ declaration or initializing w/ new
	 * or placement-new, so reads/writes thru
  	 * the result of malloc w/o initializing
  	 * the objects w/ placement-new are UB */
  	while (i--) intbuffer[i] = i;
  	return intbuffer;
  }
smitherfield··on Why has CPU frequency ceased to grow? (2014)
Should be noted that so far only Visual Studio (partially) implements C++17 parallel algorithms, although there are several third-party implementations.[1]

Apples to oranges comparison of course, since Rayon isn't [planned to become?] part of the Rust standard library.

[1] http://www.bfilipek.com/2017/08/cpp17-details-parallel.html#...

smitherfield··on Review of Vivek Wadhwa’s Washington Post Column on Quantum Computing
I’ve been impressed (read: found few/no obvious factual errors, which puts it in a minority of one among non-industry-specific news services I read) by Bloomberg’s technology reporting lately.
smitherfield··on Review of Vivek Wadhwa’s Washington Post Column on Quantum Computing
I take it that theoretical physics tends to get similarly butchered.
smitherfield··on The cost of forsaking C
Still an odd statement, since one of the authors is deceased.
smitherfield··on ZFS 128 bit storage: Are you high? (2004)
Oops, I used `#pragma pack` incorrectly in my code, but it doesn't change the codegen for the 96-bit structs other than offsets. Also `restrict` is only needed on the output argument to enable full vectorization of the 128-bit structs.

New link: https://godbolt.org/g/8uGn4h

smitherfield··on ZFS 128 bit storage: Are you high? (2004)
Packed structs are possible, to be sure, but inhibit numerous optimizations, such as (relevant to this case) the use of vector instructions and vector registers.

Changing the loop to 4 iterations for compactness' sake, (aligned) structs of two u64s generate the following, vectorized code:

https://godbolt.org/g/jB4jki

  vmovdqu (%rsi), %xmm0
  vpaddq  (%rdi), %xmm0, %xmm0
  vmovdqu %xmm0, (%rdx)
  vmovdqu 16(%rsi), %xmm0
  vpaddq  16(%rdi), %xmm0, %xmm0
  vmovdqu %xmm0, 16(%rdx)
  vmovdqu 32(%rsi), %xmm0
  vpaddq  32(%rdi), %xmm0, %xmm0
  vmovdqu %xmm0, 32(%rdx)
  vmovdqu 48(%rsi), %xmm0
  vpaddq  48(%rdi), %xmm0, %xmm0
  vmovdqu %xmm0, 48(%rdx)
  retq
And if the pointer arguments are declared `restrict`, the loop can be vectorized even more aggressively:

  vmovdqu64       (%rsi), %zmm0
  vpaddq  (%rdi), %zmm0, %zmm0
  vmovdqu64       %zmm0, (%rdx)
  vzeroupper
  retq
Either of which is much more efficient than the code generated for unaligned, packed 96-bit structs:

  movq    (%rsi), %rax
  addq    (%rdi), %rax
  movq    %rax, (%rdx)
  movl    8(%rsi), %eax
  addl    8(%rdi), %eax
  movl    %eax, 8(%rdx)
  movq    16(%rsi), %rax
  addq    16(%rdi), %rax
  movq    %rax, 16(%rdx)
  movl    24(%rsi), %eax
  addl    24(%rdi), %eax
  movl    %eax, 24(%rdx)
  movq    32(%rsi), %rax
  addq    32(%rdi), %rax
  movq    %rax, 32(%rdx)
  movl    40(%rsi), %eax
  addl    40(%rdi), %eax
  movl    %eax, 40(%rdx)
  movq    48(%rsi), %rax
  addq    48(%rdi), %rax
  movq    %rax, 48(%rdx)
  movl    56(%rsi), %eax
  addl    56(%rdi), %eax
  movl    %eax, 56(%rdx)
  retq
A smaller cost is that in non-vector code, using a 64-bit register (rax) in 32-bit mode (eax) is wasting half of the register.

IIRC, unaligned loads and stores will also, at the hardware level, stall the pipeline and inhibit out-of-order execution.

smitherfield··on Speeding Up Ruby with Shared Strings
Why couldn't you do both?
smitherfield··on ZFS 128 bit storage: Are you high? (2004)
1. Accesses through pointers type-punned to something other than `(un(signed)) char` are undefined behavior.

  uint64_t n = 0xdeadbeef;

  uint32_t foo = (uint32_t)n; // OK

  uint32_t *bar = (uint32_t*)&n; // "OK" but useless
  foo = *bar; // undefined behavior!!!

  uint8_t *baz = (uint8_t*)&n;
  uint8_t byte = *baz; // OK, uint8_t is `unsigned char`

  // Same-size integral types are OK
  const volatile long long p = (const volatile long long*)&n;
  const volatile long long cvll = *p; // well-defined
2. Structs are aligned to the member with the strictest alignment requirement, so a struct of a `uint64_t` and a `uint32_t` will be aligned on an 8-byte boundary, meaning its size will be 128 bits.
smitherfield··on Open Nazi, default GOP nominee for Congress, says not a 'single-issue candidate'
The GOP lawmaker principle: http://www.slate.com/blogs/weigel/2014/03/18/the_gop_lawmake...

Tl;dr is that only one person (the neo-Nazi perennial candidate) filed to run in the GOP primary in a safe-D seat, and state law precludes a write-in campaign. Democrats also occasionally get embarrassing nominees this way, especially in safe seats, e.g.

https://en.wikipedia.org/wiki/Kesha_Rogers https://en.wikipedia.org/wiki/Mark_E._Clayton

smitherfield··on Python’s Weak Performance Matters
>Fast code should and probably is, totally unreadable, looking like AlphaGo optimized your program.

Yes and no; multithreading and optimizing to remove branches can do a number on readability, but I find optimizing for cache locality and compile-time evaluation often makes code more readable. It depends on the language obviously.

smitherfield··on Python’s Weak Performance Matters
>in Python it's quite difficult even to reason about what's going to be in L1

The interpreter's stack?

smitherfield··on Scope exit in C++11 (2012)
While I'm a C++ fan, I'd readily concede it's much closer kin to (verbose) German than (laconic) English.

Java's even more verbose, so it probably has the stronger claim on German,* which I guess makes C++ Danish and Perl English. :)

* https://en.wikipedia.org/wiki/Andy_Bechtolsheim

smitherfield··on Scope exit in C++11 (2012)
You can do the same thing with no C++11 features other than C99 variadic macros. (IMO cleaner, too).

  #define SCOPE_EXIT(...)\
  	struct SE##__LINE__##_{~SE##__LINE__##_(){__VA_ARGS__;}}se##__LINE__##_
smitherfield··on Why is Rust difficult?
To (potentially) match Rust/C++ performance Swift needs

1. Stack and static-allocated arrays.

2. True pass-by-reference for value types.

3. A sufficiently-smarter compiler that's more often able to elide dynamic allocations, reference counting, bounds checks, vtables etc. (Lifetime semantics will help with this).

smitherfield··on Gosh Darn Function Pointers
> Ah, but what makes it an invalid reference, apart from convention?

It's an invalid reference in that a reference which does not refer to an object is either dead code, or an unrecoverable error.

There's no point in checking if a reference refers to null, because (unlike pointers) it cannot then be assigned a useful value, and also because any such check will be removed by the optimizer, because null references are undefined behavior (in both C++[1] and Rust[2]).

> Indeed, though in Rust (like most other safe-by-default languages) you do need that glaringly obvious "unsafe" keyword to perform the conversion, which is a hint that you should be checking for null at that point.

It is an improvement but (obviously) the unsafety in this case escapes from the "unsafe" block into the surrounding "safe" code and other "safe" functions.

It's also possible, even in entirely-"safe" code, to crash a Rust program by attempting to dereference a null pointer.

  fn dereference(nullable_ref: Option<&i32>) -> &i32 {
  	nullable_ref.unwrap()
  }

  fn crash() {
  	dereference(None);
  }
[1] https://godbolt.org/g/TjexTp

[2] https://godbolt.org/g/eeXAnn

smitherfield··on Gosh Darn Function Pointers
Yes, that's technically true, but you have to admit a little contrived, especially as pertaining to function pointers/references.

I'll amend my statement to "unlike pointers, valid references cannot point to a null address."

This is also true of any other language which has both nullable and non-nullable references, and a way to convert the former to the latter without accounting for the null case, such as Rust[1].

  fn pass_null_reference() {
  	unsafe { print_i32(&*std::ptr::null()) }
  }

  fn print_i32(n: &i32) {
  	println!("{}", n) // segfault
  }
[1] https://godbolt.org/g/1oUnNt
smitherfield··on Gosh Darn Function Pointers
NB: If an argument to a function is a function pointer, you can write it like a normal function declaration.

So you can write

  void transform_string(char s[], char transform(char));
instead of having to write

  void transform_string(char s[], char(*transform)(char));
When writing C++ you should use function references when possible, as references cannot be null.

  void transform_string(char s[], char(&transform)(char));
Function references unfortunately require the more complex syntax, but fortunately C++11 `using`-style typedefs are quite simple to use with function types.

  using TransformFunc = char(char, char);
  typedef char TransformFunc(char, char); // C-style typedef, same as above

  // Function pointer
  TransformFunc fptr = /* ... */

  // Function reference
  TransformFunc &fref = /* ... */
smitherfield··on 2017 JavaScript Rising Stars
Somewhat predictably, the (static, non-interactive) page took about 30 seconds to load, thanks to all the Javascript.
smitherfield··on What Really Happened with Vista: An Insider's Retrospective
Cases in point: Mozilla, Canonical, Apache Foundation...
smitherfield··on Alert About Missile Bound for Hawaii Was Sent in Error, Officials Say
Link?
smitherfield··on Kotlin: The Problem with null
>Turns out Swift does not have null pointers. At all!

Mostly true under the hood; optional value types are tagged unions (I didn't know this before reading this article and checking for myself), but optional reference types are still, as you'd expect, nullable pointers.[1]

[1] https://godbolt.org/g/QZk6wL

smitherfield··on The day I accidentally killed a little boy
That was in the mid-19th century, which was a very different world from the Medieval period. From your own link, during the 18th century Swedish 10-year-olds lived on average into their mid-50’s. From that it can be reasonably extrapolated that 10-year-olds lived on average into their 40’s in (civilizations at the level of development of) Medieval and Classical-period Europe.
smitherfield··on The day I accidentally killed a little boy
I'm already adjusting upwards for that; life expectancies didn't reach 50 (in the US) until the 1920's[1], and the posts I'm responding to are talking about the Medieval period or earlier, when life expectancy at birth would've been 30 or so. Some people did live into their 60's or longer but they were very much the exception, even among adults.

[1] https://www.seniorliving.org/history/1900-2000-changes-life-...

smitherfield··on The day I accidentally killed a little boy
No, people from out of state complain about MA drivers too (who are known as "Massholes" in the rest of New England). If you want data, take the interstate through MA and some other states and count the number of lane changes with and without turn signals.
← PreviousPage 3 of 25Next →