Currently I am writing my (second) master’s thesis. And it’s one of the hardest
work I’ve been doing ever. It’s about image and video processing. And I’m using OpenCV.
Using OpenCV is an interesting decision: if you want to create a beautiful OO architecture
for your program, you’d rather use something like Java. But I didn’t manage to run OpenCV
in Java =P
So I decided to write my code in C++. Yeah, tough decision… After spending some time implementing that,
I understood why it was not the best decision: my solution was too heavy (435 LOC) and it didn’t even
contained four major method’ implementations!
Then I sit back and thought: “Couldn’t I use C++ for video/image reading only? And write the rest of the code in a more OOP-friendly language?”. And that’s when I started looking for a language with nice syntax and OOP features (like interfaces, short array syntax, tuples/maps, etc.) and found D language.
I’ve been looking at D a very long time ago, but had never actually tried it for writing anything
more complex than a “Hello, World!” program. “That’s my star time!” - I thought.
My idea was to:
create small C++ library for video IO
create D program, which processes video, read using that C++ library
D offeres nice C++ interop, except it requires you to define classes/functions signatures you
are importing from C++. That was not a big deal for me since I had no complex classes written yet.
Standard example from a tutorial on D website works like a charm:
Compiled this one with c++ -c cpp_lib.cpp -o cpp_lib.o && dmd cpp_lib.o main.d and ran - and it worked.
Now it’s time to add some OpenCV code!
Compiling this code should not cause any troubles:
Instead, there were errors from D compiler:
WTF?! Internal compiler error?! And what’s wrong with strings?
Alright, maybe it’s caused by us,
using string type in VideoReader::readFile(string filename) method signature, which D could not
simply understand (since it’s not D’s string, rather it’s a class from C++’s STL library).
If we change string to char*, which is basically a common way to work with strings since C98, it
Yes, D supports pointers, but for interaction with C++ only. You can use pointers to create
arrays, but that’s not recommended.
Compiling our code with C++ compiler gives no errors, but D is not happy again…
Wow! That’s actually not that interesting, but simple to understand: C++ does not generate
any bytecode, which is not used by C++ program. So we should explicitly tell C++ compiler,
which methods we do want to generate code for:
The trick here is to first declare the whole class. Note: if we extract this declaration to a separate header file - it
won’t be compiled, since headers are not compile units. And if we then define(implement) methods, those implementations
will become compile units and the code for them will be generated even if they are not explicitly used in the program.
Now we’ve made something like standard C++ code - with a header and implementation.
But D compiler could not link our program again!
What? Why? We’ve declared that method explicitly! Or maybe not?.. Let’s look at our object file using nm utility:
No, we’ve got everything in place… __ZNK5Video13getFrameCountEv points to that…
Okay, that’s the mistake in D method signature:
The @disable annotation marks the method (in our case - constructor of a Video class) to be excluded from
code generation. So in our case we won’t have a default constructor for Video class, which D generates for us
implicitly. And when we try to link our code, linker can not find the code for a no-argument constructor. So we then
have two options: either we define a no-argument, “default” constructor in our C++ library, or we prevent D
from generating it for us.
Yeah! Our code compiled and linked successfully! Now let’s run it:
What? Wrong again?! Okay, that’s really strange. And no debugging information provided.
Adding some debugging info with writeln()’s shows it’s caused by the getFrameCount() method call:
Maybe it’s because D and C++ have different unsigned int type size?
Seems like no:
The trick here is that signature for constant method in C++ differs from such in D:
If we build and run our code now, everything works fine:
These simple errors were hard to find and fix intuitively. But what does it have in common
with beautiful code? Stay tuned for more`!