Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

07 December 2015

Commenting code

At some point I took to heart admonitions to not write comments that simply repeat what the code clearly says. A discussion with a co-worker, Achint, not too long ago made me realize that this is bad advice. And I should have know better.

“Don’t repeat yourself.”

—Dave Thomas & Andy Hunt

In (human) language, redundancy is a feature.

—me

In programming, the DRY principle is rightly lauded. Not just for code itself but for every bit of information in a software system.

But it’s the opposite for human language. In this case, redundancy makes things clearer. Saying something in both English and code will help the human reader (including your future self) understand the code better and faster.

Certainly, there are situations in which code is clear enough on its own, but—in general—it’s probably better to err on the side of more comments. I’ve seldom seen (or written) code that had too many comments.

But I have sometimes seen code with too many comments. The most common is doxygen boiler plate without any useful content. The other is some of the code written in “literate coding” style.

17 November 2015

Book v. iPad Air v. iPad Pro

I put together an online iCloud photo album with some pictures comparing books with the same or equivalent e-book on iPad Air and iPad Pro.

While the iPad Air is a better size for typical novels and articles, the iPad Pro is (IMHO) better for textbooks† (like technical books and RPG books) and comic books.

Digest-sized RPG books are often better on the Air. Although, the Pro does allow viewing two of them side-by-side.

Unfortunately, to get the two books side-by-side I had to load them into different apps. (In this case, iBooks and PDF Expert.) Although I haven’t played with PDF Expert enough to know what it can do. My PDF app of choice, GoodReader, hasn’t been updated to support side-by-side or to fully support the iPad Pro yet.

Being able to view two arbitrary pages in the same PDF side-by-side could be useful too. While you could do this with the two apps workaround, it would be better if a single app added such a feature. GoodReader has the ability to open multiple pages from one PDF in separate tabs, so that seems a reasonable addition to better support the iPad Pro.

But being able to view a book at full iPad Air size on one side of the Pro while having another app—e.g. Pages, UX Writer, Evernote, etc.—at full iPad Air size on the other side seems promising.

†Ironic that the word “textbook” seems á propos to me here since what distinguishes these from typical novels and articles is that they have lots of images, tables, and diagrams in addition to text.

20 October 2015

Should GSL string_view should be string_ref instead

(Another one for C++ programmers)

Time for some bikeshedding.

It looks to me like GSL string_view and the library fundamentals TS (hereafter LFTS) string_view have different goals. Also, I have heard it said that the “_view” in LFTS string_view was meant to emphasis that it was read-only.

Perhaps GSL string_view should be called string_ref to distinguish it from LFTS string_view and because it isn’t strictly a “view”?

LFTS string_view’s goals are to be a (as much as possible) drop-in replacement for “const std::string&” without the memory allocation and copying that it sometimes requires. GSL string_view’s goals, however, are safety and being able to replace any use of a raw char array as a function parameter. These differences manifest in (at least) two ways. First, LFTS does not allow modification of the underlying data while GSL string_view does. (Although a const GSL string_view can be used.) Second, LFTS string_view copies all the const member functions of std::string while GSL string_view—just an alias for GSL’s array_view—prefers free functions for string-specific operations.

It doesn’t look like it will be easy to serve all of those goals without getting ugly. As much as it would be a shame to have two versions of somewhat similar concepts.

(I’m not as familiar with N3841 array_view yet, so I’m unsure if there is an analogous issue for array_view.)

Update (6 November 2015): Good news. In the wake of the October 2015 meeting in Kona, GSL’s array_view and string_view will be renamed span and string_span.

19 October 2015

Parameterize by data member in C++

(For the C++ programmers in the audience.)

This is the story of me finding an unused tool at the bottom of my C++ toolbox and figuring out what it did.

I started with some structures that looked like this. (And, of course, changing the structures was not an option.)

struct Foo {
mint a;
mint b;
mint c;
mint d;
m/*etc*/
};

const int foo_count = 10;

struct Bar {
mFoo foo[foo_count];
m/*etc*/
};

I needed to write some code that looked something like this.

int foo_calc_a(const Bar& bar1, const Bar& bar2)
{
mint result = 0;
mfor (int i = 0; i < foo_count; ++i)
mmresult += bar1.foo[i].a - bar2.foo[i].a;
mreturn result;
}

But I needed a function like that for multiple members of Foo, and I didn’t want to copy & paste that function for each data member.

I could do it the old school way using offsetof. (I’ve fancied it up with C++-style casts and a C++11 lambda.) And then we have an example call for member a.

int foo_calc(const Bar& bar1, const Bar& bar2, std::size_t offset)
{
mauto f = [&offset](const Foo& foo) {
mmreturn *(reinterpret_cast(
mmmreinterpret_cast(&foo) + offset));
m};
mint result = 0;
mfor (int i = 0; i < foo_count; ++i)
mmresult += f(bar1.foo[i]) - f(bar2.foo[i]);
mreturn result;
}

auto result = foo_calc(bar1, bar2, offsetof(Foo, a));

Of course, we get no help from the compiler here since we’ve told it, “Trust me!”. (While writing this version, I did write two bugs that the compiler missed. The improved version of the function—which I’ll show you later—gave the right answer as soon as I got it to compile.)

That works, but surely we can do better! I tried a few other solutions, but we’ll skip to the one I settled on.

While I was reading something else, I noticed a mention to “pointer to data member” that suggested it was more than what I thought it was at face value. This lead me to...

The operators −>∗ and .∗ are arguably the most specialized and least used C++ operators.

—Bjarne Stroustrup, The C++ Programming Language (4th edition), §20.6

The funny part was that I immediately recognized that I’d read this section before, though clearly I never fully grokked it.

You get a PMD (pointer to member data) with the ampersand operator.

&Foo::a

What type is it? It is a “int Foo::*”. A pointer to an int member of Foo.

int Foo::* pmd = &Foo::a;

The thing is, this isn’t really a pointer. It is an offset. Although it is a typed offset. Like any offset, we need a pointer to an instance to “add it to” to make it a pointer. How do we do that? With those specialized operators mentioned above.

Foo foo;
Foo* p_foo = &foo;
foo.*pmd;
p_foo->*pmd;

...and thus, foo_calc becomes...

int foo_calc(const Bar& bar1, const Bar& bar2,
mint Foo::* pmd)
{
mint result = 0;
mfor (int i = 0; i < foo_count; ++i)
mmresult += bar1.foo[i].*pmd - bar2.foo[i].*pmd;
mreturn result;
}

auto result = foo_calc(bar1, bar2, &Foo::d);

Viola!

But at what cost? You should, of course, measure for your own environment. For my code, this was no slower than using offsetof. There’s really no reason for it to be, since it is essentially the same thing. Just with some different syntax and the compiler checking your work more.

So, if you’re tempted to use offsetof, use a “offsetpointer to member data” instead.

23 September 2015

JetBrains

...or “What for brains?”

Final update on the JetBrains Toolbox announcement

I’d been waffling on whether to buy JetBrain’s CLion when they announced their move to a subscription model. They’ve made the decision easy for me.

I do like to see companies admit their mistakes, and I like to reward that. But this has all the hallmarks of a leadership that is customer-unfriendly and not smart. I am not going to reward that.

13 August 2015

A note about C++ std::accumulate

For any C++ programmers...

When using std::accumulate, the return type is inferred based on the third parameter. So be sure that the third argument is the same type you expect it to return. See this example.

(For some reason codepad’s C++ compiler complained about using 0ULL, so I used static_cast<uint64_t>(0) instead.)

31 January 2015

C sizeof structure member

Something I don’t think I’ve run into with C before.

It can be so hard to come up with a sensible example. So just ignore whether you think I should be doing this. Assume that something similar made sense in context.

typedef struct Foo {
    char uuid[37];
    int value;
} Foo;

char main_foo_uuid[sizeof(Foo.uuid)] = "";
//Compile error!

Doing sizeof(Foo) is fine, but sizeof(Foo.uuid) is not.

One solution is do declare a dummy instance of Foo.

Foo dummy;
char main_foo_uuid[sizeof(dummy.uuid)] = "";
//Works!

But there’s a trick to avoid declaring the dummy: Cast NULL to a pointer to Foo, and use that as your dummy.

char main_foo_uuid[sizeof(((Foo*)NULL)->uuid)] = "";
//Works!

Which makes you wonder why the language couldn’t just support sizeof(Foo.uuid).

27 January 2015

Other people’s code

Programmers dread reading code written by another programmer. Why is it so hard to read other people’s code? I don’t know, but here are some thoughts.

In C, it is because of the limited ability to express abstractions. Code of any complexity tends towards using function pointers and macros and other techniques that obscure things.

In some languages, like Perl, it is because everyone uses a different subset of the language. In the extreme case, this can also mean completely different styles of programming in the same language.

With some languages, like Scheme, it is because the ability to build powerful abstractions means that code of any complexity essentially becomes another language embedded in the original. To understand the code, you have to learn this new, project-specific language.

08 January 2015

What is great about C++?

There is plenty that is not great about C++, but I do enjoy the language. So I wonder why. This may be a reason.

A myth from Stroustrup’s article on C++ myths: “For efficiency, you must write low-level code”

You can say that often people over-emphasize efficiency. You can certainly point to places where C++ has failed at this or where the implementations have not yet lived up to the promise. But C++ does demonstrate that you do not always have to trade efficiency for abstraction.

12 June 2014

Swift

If you had told me before WWDC 2014 that Apple would introduce a new programming language, I would sadly shake my head. So many programming languages are created without leveraging any of the lessons of languages that have been around for decades. My general attitude is that there is little reason to create a new language instead of building off an existing one.

So far, however, Swift has impressed me. I can’t really find much to complain about.†

You could argue that in many ways Swift does build off Objective-C rather than being a new language, but that argument sells Swift short. This is a very impressive design.

†OK...here’s a...observation: It seems like having some kind of cycle-detection to augment ARC ought to be there.

25 March 2014

Why can’t Johnny reverse a linked list?

Colleges: You are graduating computer science/software engineering students who don’t understand pointers, floating-point, or what a closure is. (And I don’t mean that they don’t understand the terms; they don’t understand the concepts.)

It is so frustrating when I don’t get to talk to an interview candidate about higher level concerns because they don’t know the fundamentals. (It is even more frustrating when I do get a chance to talk about higher level concepts only to find they don’t have a grasp of those either.)

Even if you don’t believe that pointers and floating-point are as fundamental to the working software engineer as reading is to a secondary school student, at least tell them not to put C on their resume if they don’t understand these concepts. And tell them not to list Javascript if they don’t understand floating-point or closures.

I’m not so idealistic to think that a degree can ever be a guarantee of anything, but the current situation is that the degrees you are handing out are worthless.

Students: I don’t think the moral of the story is to not go to college. I may not have graduated, but college did expose me to things I might not have been exposed to otherwise. Understand that college will not prepare you for your career. College is an opportunity for you to prepare yourself for your career. You will get out of it what you put in.

12 February 2014

CodeRunner

If you are a C++ programmer with a Mac, buy Nikolai Krill’s CodeRunner from the Mac App Store. It is great for banging out quick experiments. Pick C++, write the code, hit the run button.

It also does AppleScript, C, C#, Java, Javascript, Lua, Objective-C, Perl, PHP, Python, Ruby, and shell scripts. And you can configure more yourself.

31 October 2013

Smart enough?

A tweet quoted in Why Deprecating async() is the Worst of all Options:

The fact that top men standardized something already broken tells me I'm not smart enough to use C++11 or 14 in production

Unrealistic expectations of perfection are not smart. Rejecting all the goodness in C++11 because of the issues with std::async and std::future is not smart. If you don’t come across the pitfalls when learning about C++11, you’re not being smart in how you learn about C++11.*

So, I guess I agree, but I don’t think this has anything to do with people involved with C++11. ☻

*I currently only get to write C++11 in my spare time, and nigh everything I’ve read about std::async mentioned the known issue.

11 September 2013

Ad hoc programming

Does everyone need to learn programming?

Obviously, not all program development time is measured in man-years. One could no doubt write a program for generating anagrams in a couple of days, [...]

This is intentionally a trivial example, but it is practical tasks of this scale that are exactly why you should learn to program.

It isn’t because computers are becoming increasingly ubiquitous. Most people aren’t going to write the software for appliances that happen to have computers in them. Most people aren’t going to write application software for general-purpose computers.

It’s the small tasks that are never going to be a bullet-point feature of an appliance or application where most people can benefit from learning to program.

If you’ve ever written formulas in a spreadsheet application, you’ve already done some programming. And while spreadsheets are appropriate for some tasks, there are better ways to program that aren’t really any more difficult that are more appropriate to a much wider array of tasks.

[...] though it would take the average neophyte the same couple of days merely to type in the 75 to 100 lines of code required. Not only can a single misplaced colon or parenthesis mark foul up the works, but it often takes an enormous amount of time to discover such a seemingly minor error.

Programming is, indeed, sometimes like this. But with good tools and experience, it is the exception rather than the rule.

That said, programming is not for everyone. If you like math, you will probably enjoy programming. If you don’t like math, you probably won’t. So, the benefits may not be worth the costs for everyone.

02 September 2013

Lambda

Playing with λ-calculus is fascinating. That everything we do with computers can be represented simply with unary functions is mind-blowing.

But when I think about it too much, I begin to doubt the applicability of λ-calculus to what we actually do in practice. We don’t use Church numerals. We use two’s compliment binary integers and IEEE floating-point and—when necessary—various arbitrary precision numbers. Our conditionals aren’t based on Church Booleans but on conditional instructions built into our microprocessors. Our lists may be built out of pairs, but our pairs aren’t functions. We don’t use the Y-combinator to express recursion; we simply give our functions names, which get turned into jumps.

Granted, closures in Scheme—much like functions in the λ-calculus—are used to build higher level features. (And, of course, the keyword for creating closures is “lambda” in reference to the λ-calculus.) But lots of the lower level stuff isn’t built from closures because it wouldn’t be efficient enough. (Could it be if the effort was made to design hardware for it?)

Edit: Here’s some example code.

09 July 2013

Form the sweating-the-details habit early

A Short Quiz About Language Design:

That may be uncomfortable at first glance, but give it a moment. Sure, a vertical bar will end up in a string at some point—regular expressions with alternation come to mind—but the exceptional cases are no longer blatant and nagging, and you could get through a beginning class without even mentioning them.

Glossing over this kind of thing is a huge mistake. To write decent code, a programmer has to keep many such edge cases in mind all the time. It’s a struggle to do so, and it’s a habit that needs to be formed as early as possible.

03 June 2013

Scheme implementations

One of the difficulties in getting started with the Scheme programming language is picking an implementation. There are a bunch. Many of them are very good. Each has strengths and weaknesses. But those strengths and weaknesses don’t always readily line up with uses. So, recommending an implementation can be tricky.

Here is a pretty good guide to picking an implementation: “an opinionated guide to scheme implementations

I know a lot less about Scheme than (wingo). I just play with it and use it instead of Bash/Perl/Python/Ruby whenever I can at work. Still, I was a Scheme newbie once, so here’s my suggestion:

If you’re using Linux or BSD, check to see if Guile is installed. (If you’ve got Mac ports or fink installed on your Mac, you might fall into this category as well.) There are things I love about Guile, and there are things I hate about it. But it is hard to argue with it already being installed on your machine. Grab a copy of SICP or The Little Schemer or whatever and go...

If you’re on Linux or BSD and you don’t have Guile installed, check your package manager for it.

If you don’t have Guile or if you’re ready for something more than Guile, get Racket. While the people working on Scheme standards are trying to figure out how to please academics and pragmatists, Racket has built a Scheme that is good for learning/teaching the language and has much of the “batteries included” that some other languages claim you should expect.

If you want Racket but without the GUI bits, you’ll have to dig a bit for Racket Textual.

Once you’ve had a taste of Scheme with Guile and/or Racket, then you can start to delve into what makes all those other implementations unique.

18 May 2013

Fake call/values

For the programmers in the audience. Knowledge of Scheme is assumed.

(λ)

Lisping currently comes with TinyScheme. TinyScheme doesn’t support multiple return values (i.e. values and call-with-values). So, I did this...

;;; How to fake multiple return values
(define values list)
(define (call-with-values producer consumer)
  (apply consumer (producer)))

It was a bit surprising to me that it was that easy to fake.

This isn’t quite equivalent to the real values and call-with-values. e.g. Given a single argument, the real values function returns that argument, but my fake one returns a list instead. Which, in fact, broke another part of my code where I was using values as an identity function rather than for returning multiple values.

;;; The real values function
(values 5) → 5
;;; My fake values function
(values 5) → (5)

I imagine that real multiple return values can be more efficient than a list. On the other hand, it seems like a smart compiler could optimize-out the list in the fake version too.

Edit 21 May 2013: There is some interesting discussion here.

[...] Matthias Blume argued passionately against the presence of values/call-with-values in Scheme on the grounds that they add nothing to the language as a language—that is, they grant no additional expressiveness beyond what is already possible with list and apply [...]

The primary arguments in favour of values/call-with-values were that they allow implementors to optimise generated code in ways that are impossible or more difficult in the list/apply case.

17 May 2013

Lisping

Lisping is an iPad editor for the Scheme programming language (or Clojure). It is pretty much what I imagined in 2010 when I wrote about a Viaweb/RTML-style Scheme editor.

21 January 2013

My dream text editor and word processor

There’s a discussion on Branch about Your Dream Text Editor / Word Processor. I submitted an answer, but it won’t show up unless I get approved to join the branch. In fact, there doesn’t even seem to be a way for me to see what I wrote until/unless I get added to the branch. Weird. (But then it took me a while just to figure out how to add the branch to my Branch “drawer”.) So, it goes here too.

My dream text editor would be mostly like Vim, but with Scheme underneath.

I’ve had to work on enough systems where vi was the only practical editor that I found it easier to use Vim on the systems where I could install something more powerful. I’ve really come to like it except for its ad hoc scripting language. I’d envy the Emacs people except that I think elisp would just annoy me by being almost Scheme. ^_^

My dream word processor would be something akin to Amaya or UX Write. I want the output to be clean HTML. I want to be able to do semantic formatting as I write without having to type raw HTML, LaTeX, or Markdown.

Plus I’d like a high quality HTML to PDF/print converter. HTML+CSS has features that ought to allow generating LaTeX quality print.