Wednesday, October 24, 2018
Changed name of blog
(Note: I've changed the name of this blog to avoid any association with the recent bombings. I disavow violence.)
At Amazon, the Principal most associated with "Scrum" and "Agile Development" used to say that you should not consider a software feature shipped until it was "Done Done Done" -- in other words, not just done, but done in all ways you can think of.
Hence, "Dunn Dunn Dunn".
Thursday, June 18, 2015
Using C++11 in Travis CI
There are many strange solutions, but there is now a better way to do this.
sudo: false
language: cpp
compiler:
- gcc
- clang
install:
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
- g++-4.8
- clang
The explicit sudo: false will let it build in Docker (for speed) even if you have a pre-docker repo, according to Travis support.
Thanks to solarce at Travis support for noticing my error and fixing the docs.
sudo: false
language: cpp
compiler:
- gcc
- clang
install:
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
- g++-4.8
- clang
The explicit sudo: false will let it build in Docker (for speed) even if you have a pre-docker repo, according to Travis support.
Thanks to solarce at Travis support for noticing my error and fixing the docs.
Friday, May 8, 2015
Deceptively simple interview questions
Someone posted this blog to reddit:
Then, someone else posted this correction:
Embarrassingly, the original poster had stated:
The moral is not to assume that you know the answer to your own interview question. Be humble. Let the interview be a discussion. Maybe you will learn something.
Then, someone else posted this correction:
Embarrassingly, the original poster had stated:
I never said that you'll be hired if you know how to answer these problems, but I won't consider you if you can't.Therefore, he would not hire himself!
The moral is not to assume that you know the answer to your own interview question. Be humble. Let the interview be a discussion. Maybe you will learn something.
Wednesday, April 29, 2015
git-fat for large files
GitHub recently added support for largefiles. If you want to share repos globally, that's fine. But for work within a corporate network, I like git-fat. It has few dependencies -- just plain python and rsync -- and caches files in /tmp. It's much simpler than alternatives like git-annex or git-lfs, which are better when you need the option to store files in S3, etc..
However, there is one problem with all these: They still deal with expensive checksums for many operations. This is partly to keep things simple -- letting git operate on files directly. But even just copying large files is slow, let alone checksumming. It's much faster to store URLs and to let the plugin update symlinks (or hardlinks) and handle caching. If you want a checksum, that can be encoded into the URL. Another advantage is that you can store whole directories, rather than individual files.
That is a plan I am working on with a friend. All large files would be read-only, unless explicitly "opened".
For now, git-fat works pretty well.
However, there is one problem with all these: They still deal with expensive checksums for many operations. This is partly to keep things simple -- letting git operate on files directly. But even just copying large files is slow, let alone checksumming. It's much faster to store URLs and to let the plugin update symlinks (or hardlinks) and handle caching. If you want a checksum, that can be encoded into the URL. Another advantage is that you can store whole directories, rather than individual files.
That is a plan I am working on with a friend. All large files would be read-only, unless explicitly "opened".
For now, git-fat works pretty well.
Sunday, February 15, 2015
Google C++ Style Guide
- https://www.youtube.com/watch?v=NOCElcMcFik (Titus Winters at CppCon)
For a longer discussion, see:
- http://www.reddit.com/r/cpp/comments/289n27
- http://stackoverflow.com/questions/26441220/googles-style-guide-about-input-output-parameters-as-pointers/26441753#26441753
- http://stackoverflow.com/questions/7557258/jsoncpp-formating-problems/28521926
Wednesday, January 7, 2015
C++: STL Iterator confusion
Recently, folks at my last company got confused with STL iterators.
- They used boost::python to create an InputIterator, using stl_iterator.
- They used is_sorted() to check whether the underlying list was sorted (of course).
- They then looped over their iterator.
That was a mistake. An InputIterator is single-pass, so someone obviously forgot to read the documentation.
But this highlights a problem with STL. is_sorted() actually requires a ForwardIterator. At that link, you can see that a ForwardIterator might be "mutable", meaning that it can be written into. But is_sorted() takes a copy of an iterator, and it certainly does not write into it. There can be no issue of side-effects, right?
Wrong. You can pass an InputIterator if you want, at your own risk. is_sorted() might still return the correct result, but the original iterator (which was copied for the call to is_sorted()) might now be invalid.
So the question became whether it was safe to pass an Inputerator to is_sorted(). In general, the answer is "No". Look at representative source code:
template <class ForwardIterator>
bool is_sorted (ForwardIterator first, ForwardIterator last)
{
if (first==last) return true;
ForwardIterator next = first;
while (++next!=last) {
if (*next<*first) // or, if (comp(*next,*first)) for version (2)
return false;
++first;
}
return true;
}
That function requires a copy of the original "first" iterator. "first" and "next" must both be valid during the entire function, and that is not guaranteed for an InputIterator.
However, the boost::python InputIterator is actually a memoized iterator. If you increment it, then the next value for any copy will no longer be the value after what the copy points to. But the copy remains valid for reference. So is_sorted() is fine, as long as no further iteration is performed later.
The problem is that STL is missing a concept between ForwardIterator and InputIterator. So is_sorted() is given the more restrictive designation.
Another way to look at this is that C++ templates are insufficient for practical iterators. The following is closer to the function we really want:
template <class ForwardIterator>
bool is_sorted (ForwardIterator first, ForwardIterator last)
{
if (first==last) return true;
ForwardIterator next = first;
auto prev_value = *first;
while (++next!=last) {
auto next_value = *next;
if (next_value<prev_value);
return false;
prev_value = next_value;;
}
return true;
}
But that has problems too. Suddenly, the underlying type must be copy-constructible, and those copies could be expensive. We could use a pointer, but a pointer to what? If we don't make a copy, then there is nothing to point to.
We need an extra version of this algorithm which can safely accept InputIterators, with the implication that there will be copies of the underlying data. But it would need a different function name, and it would confuse everyone.
What we really need is the concept of "Iterator with invariant current element (unless underlying container is modified) but possibly variant subsequent Iterator". Lots of iterators actually work that way. But it would probably confuse people even more.
Tuesday, September 16, 2014
Reactive Programming
This is hard for me to explain yet, but here are helpful links:
Basically, state is passed down, and events go up. Component A creates Component B, passing parts of A into B as immutable properties, and setting call-backs on B to call into A. Most components are re-created repeatedly.
Benefits:
- Data-flow is clear and consistent.
- Mutable state is isloated and minimal.
- The entire architecture is highly scalable.
Subscribe to:
Posts (Atom)