
The bell has tolled for rand() - StylifyYourBlog
http://cpp.indi.frih.net/blog/2014/12/the-bell-has-tolled-for-rand/
======
jlebar
Not to focus on a question unrelated to this blog post's point, but

* "auto main() -> int" could be just "int main()".

* "auto v = vector<int>(20);" could be just "vector<int> v(20)".

* "auto print_value = [](auto&& v)" could be (I'd argue _should_ be) "auto print_value = [](const auto& v)".

"auto" is useful, "auto" is great. But "auto" is not an end in and of itself.

(Bring on the C++(11) haters, blah blah.)

~~~
forrestthewoods
I'm not convinced auto should ever be used for anything other than iterators
and anonymous types. There are other instances where it's relatively fine to
use. Perhaps a few where it's even slightly better to use. But in C++11 I
think it's by far best to limit it to there be explicit cases I mentioned.

In C++14 I'll extend support to lambdas in some cases but will need to
experiment to say for sure.

~~~
fafner
Sorry, but your comment lacks substance because you don't provide any argument
for the way you think. Why should it only be used for iterators and anonymous
types?

There is a pretty good argument for using the

    
    
      auto var = T{val};
    

style of defining variables. The {}-initialization won't narrow literals. You
can find more discussion about this in GotW.

Maybe you have a good reason for not liking the style and there certainly can
be arguments against it. But from experience I find that many people opposing
more use of auto simply oppose it because it is different to their old ways.
Therefore I'd like to see a proper argument for your comment.

~~~
forrestthewoods
I specifically referred to C++11. And I believe your example with the T{val}
is C++14 so I don't know much about it.

My experience is working on video game engines with other people. As a senior
developer a large part of my job is jumping through a wide range of systems
written by other people to debug problems, identify ways to increase
performance, add features, etc. There's also a lot of code written by people
who have moved on to other jobs.

We've had quite a bit of code that was full of autos. In my experience thus
far auto has never made code more significantly readable or easier to
understand than not using auto. (excluding iterators/lambdas) Not only has
auto not made code easier to comprehend the use of auto has made it
significantly more difficult to understand on more than a few contexts. If
deducing a type as a human reader of text requires backtracing a half dozen
calls of code across who knows how many lines of code, and even files, then
I'm gonna be justifiably grumpy. It's a huge burden. And for what benefit?
Damn near nothing in my experience so far.

~~~
MrDosu
This is something an IDE does for you...

~~~
forrestthewoods
In theory, but not in practice. Visual Studio starts off great but it
eventually chokes and dies for C++. Tools like Visual Assist can extend the
lifetime but eventually it too will fail. This is true for every game and
every engine I've ever worked on.

I now do 100% of code editing in Sublime Text. Other people use other text
editors. I'm now of the opinion that code bases should be useable and
searchable in plaintext form. It's not difficult and even with an IDE makes
things better imo.

~~~
MrDosu
I would (almost) completely disagree with this.

C++ support in VS is horrible, that's correct, but having the ability to be
supported by compiler services that can parse (invalid) code is a major
milestone when it comes to handling more complex codebases.

It does not matter how smart you are, the easier it is for you to understand
and reason about the code, the more will fit in your head.

Refactoring is just one of the many amazing tools that make me a much better
and more productive programmer today then I was without when using vi in the
90s. Add in static analysis, intellisense etc... Every bit of complexity that
tooling can hide from you is worth gold.

Reality for C++ is grim though in this regard. Let's hope we get better
compiler services for it soon.

~~~
forrestthewoods
I agree that the easier it is to understand and reason about code the better.
That's why I'm opposed to most uses of auto. It makes code harder to
understand. It might not make code harder to understand if it was used with
tools that doesn't exist. But those tools don't exist. I'm constantly re-
evaluating my opinions and for auto I keep reaching the same conclusion. I
pray that someday new tools are released that make my work life better. When
they are some of my re-evaluations, related to auto or otherwise, will
certainly change. But sadly that day is not today.

~~~
MrDosu
Just interested: Do you use static analysis tools (like for example coverity)
in the gamedev industry?

------
gpvos
Interesting to see that OpenBSD recently went the other way: break the
standard and make rand() a good random generator by default. Even to the point
of making srand(time(0)) a no-op.

[https://news.ycombinator.com/item?id=8719593](https://news.ycombinator.com/item?id=8719593)

~~~
brudgers
That's part of exactly what makes the problems with rand() so intractable.
Whether a program performs as specified is an arbitrary function of real world
state.

------
DonHopkins
"The C random library has always been… to put it politely… less than ideal.
Okay, it’s pretty fucking horrible. It’s so bad that the C standard itself
suggests you’d be better off not using it."

Back in the days 4.2 BSD or so, the BUGS section of the manual entry for rand
understatedly mansplained that it had "bad spectral characteristics". In fact,
it was so bad that the lower bit alternated between 0 and 1 every time you
called it. Hard to miss that bright line on a spectrogram.

If you couldn't figure out what to expect from such a forthright disclosure in
the manual, then you were in for quite a shock when you did the obvious thing
and tried to use "rand() & 1" to simulate flipping a coin!

~~~
lloeki
If I were to use C, what should I be using instead of rand(3)?

A cursory look at rand(3) SEE ALSO hints at candidates but random(3) seems to
hardly fare better†, arc4random(3) isn't available on glibc.

† A few notes about rand as the parent suggests, but nothing regarding mod
bias, srandom initial state, or threads:

> It returns successive pseudo-random numbers in the range from 0 to (2
> __31)-1. The period of this random number generator is very large,
> approximately 16 _((2_ *31)-1).

> All of the bits generated by random() are usable. For example, `random()&01'
> will produce a random binary value.

~~~
tedunangst
There are several paths to getting arc4random or something like it.

You can just use it and optionally tell people to link with e.g. libcrypto
from libressl.

You can include the portable code yourself, though that's yucky. Aging
software that includes never updated very early versions of arc4random is
actually kind of a problem because that code still gets used when better
versions are available.

You can link with [https://github.com/nmathewson/libottery-
lite](https://github.com/nmathewson/libottery-lite) which is approximately
arc4random with a different name.

Some combination of the above.

For example, sqlite3 includes an arc4random workalike (rc4 rng), but doesn't
discard the early stream (critical because it leaks the key) nor include any
degree of fork safety. Nor does it check if the host provides a better
version. sqlite3 shipped with OpenBSD is patched to use libc arc4random
instead, but building from source means you're back to square one. Not a big
deal in the case of sqlite3, but try not to build something that doesn't
improve as the world around it improves.

------
leni536
Why is a specific random generator should be in the standard at all? Random
generators are quite a dangerous area.

Picking one is not without compromises: Do you want your PRNG fast? Or do you
want it cryptographically secure?

It could become obsolete in less time than expected. It's mostly true for
CSPRNGs. Maybe that's why they are considering Mersenne Twister which is "good
enough" for many use cases but not meant to be cryptographically secure. Sure,
I'm using it right now for physics simulation and it's certainly good enough
for that and it's hard to imagine a case where a 623-dimansionally
equidistributed PRNG could fail. But it most certainly can if it can't be used
for cryptography. It is _much_ better than rand() though and one could argue
that it will be good enough 99% of the time. The problem that you can't
replace it if it ever becomes obsolete since some software depends on the
predictability and still random like features of PRNGs (like game map
generators, digital art, etc...).

I think the one boost library they should standardize is boost's random
device. PRNGs could become obsolete but "truly random" will always mean the
same. However it's not trivial that one has access to a truly random source
and in that case it should fall back to fail. At least it could kill the
practice of seeding with time.

~~~
StephanTLavavej
std::random_device is part of C++11, and VC's implementation guarantees that
it's crypto-secure.

~~~
tedunangst
The problem is the standard doesn't guarantee that, so people will inevitably
read the standard, decide that they can't actually trust random_device, and
then build their own, much worse version.

------
arsv
The title is grossly misleading. It should read "C++17 people choose Boost
over std::rand() for their RNG needs" or something like that, a hardly
surprising statement since C++17 people would choose Boost for pretty much
anything else as well.

In particular, it has little to do with rand() (as in rand(3) from libc),
which has its uses as well as well-known alternatives within C world.

As a side note, it's funny to see fresh new C++ code that boils down to
srand(readintfrom("/dev/random")), except /dev/random is now given an
"abstract standard name" random_device.

And that part about limited seeding options. Beats me Boost (the library)
alone won't fit in the memory of a device with 16bit ints, so inability to
seed the RNG will be among the least of their problems.

~~~
unscaled
Some C++ programmers love writing cross-platform code, with platform including
non-UNIX platforms here, so /dev/random just won't work. That's why you'd need
an "abstract standard name".

One of the largest user audiences of C++ is game developers, and (excluding
mobile) 99% of their target platforms don't have /dev/random, so it's
perfectly normal to want an abstract random device.

As a side note, if you've actually read the article through you'd learn that:

1\. The Boost.Random stuff entered the C++ standard back in TR1 (published in
2007), way earlier than C++17. 2\. Even if your seed is perfectly random,
rand() would give you crappy distribution. 3\. srand()/rand() is not re-
entrant, which makes it a really bad idea to use it in any codebase that has a
chance to grow larger one day. 4\. Even if the seed is truly random, rand
would give you crappy distribution and thus it has no legitimate uses other
than making a game where its easy to cheat. 5\. None of the rand()
alternatives is in the C standard, and most are highly platform-specific. C++,
on the other hand, had very good standard random generators for the last 8
years or so, which is very nice for the language that didn't even have
standard strings for 15 of its existence.

------
DonHopkins
"(not to be confused with std::mem_fn() – not the dropped ‘u’)" \-- note the
dropped 'e'.

