Posts for 2010 March
Operator sizeof (AKA Reading Berkeley's FM, take II)
Post by Nico Brailovsky @ 2010-03-29 | Permalink | Leave a comment
Last time I told you about an evil snipet I found on Oracle Berkeley DB's manual:
skey->size = sizeof((struct student_record *)pdata->data)->last_name;
And we concluded it's trying to... well, dereference a number. And yet it compiles. What the hell is going on there?
The answer here is in the subtleties of the sizeof operator. That's right, operator, not function. Plus is an operator. Less is an operator. * is a (unary) operator. sizeof is a unary operator too. The relevance of this is that operators can behave in more bizzare ways than functions do. In this case there's a difference between this two lines:
MyClass x;
int a = sizeof(MyClass);
int b = sizeof(x);
A very subtle difference. Can you spot it? a and b will have the exact same value, rest assured. The difference is in the operator itself: sizeof MUST have parenthesis when applied to a type name, yet parenthesis are optional when applied to an instance of a datatype, so this code is legal:
MyClass x;
int a = sizeof(MyClass);
int b = sizeof x;
Oh, wait, the fun doesn't stop there: sizeof also has bizarre precedence order, meaning it won't get applied as you expect it. So, this is valid too:
struct MyClass { int y; } x;
int b = sizeof x->y;
Can you see where we are going? Knowing that sizeof will be applied last lets you write something like this too:
void ptr = ...
int b = sizeof((X)ptr)->y;
Which means nothing else than "store in b the size of member y in struct X. It should be easy to see why BDB's example does compile, and why did I spend half an hour trying to understand the reason it compiled fine.
By using some more casts and a clever arangement of parenthesis you can come up with a great job security device.
In reply to this post, Gregory Burd commented @ 2010-03-29T18:26:21.000+02:00:
Nico,
Do you really hate "Berkeley" or just the ANSI C programming language? :)
"DB" is a type name for a struct and part of our ANSI C API while the "Db" is it's counterpart in C++. "Db" is a C++ Class name. You'll choose one or the other depending on the language you use. DB if you're programming in C, Db if you're programming in C++. Make sense?
The use of the ANSI C sizeof operator works perfectly in our manual, as you discovered, but I'll agree that it is hard to parse at first. You have to understand that sizeof is an operator and the precedence of it verses other C operators to fully get how that single line of code works. It's a bit obtuse and we are considering making the example code less complex in the next release.
I hope that helps.
-greg
Original published here.
In reply to this post, nico commented @ 2010-03-29T18:59:07.000+02:00:
“DB” is a type name for a struct and part of our ANSI C
API while the “Db” is it’s counterpart in C++. “Db” is a C++
Class name. You’ll choose one or the other depending on
the language you use. DB if you’re programming in C, Db
if you’re programming in C++. Make sense?
Sorry, it does not. Not using a namespace is by itself a bad thing but having two similar things which differ only by the capitalization of their name is error prone and leads to strange error messages, not to mention that it's one of the things that you get told not to do in any first programming class.
You can live with it; it is a poor programming practice regardless.
The use of the ANSI C sizeof operator works perfectly in our manual, as you discovered, but I’ll agree that it is hard to parse at first.
Again, I disagree: it's plain wrong to justify it saying it works that way when a much clear option (using parenthesis) exists, without any downside.
I can write C++ programs using only a big main. It works but it's wrong. I can use a sizeof operator to obfuscate my code, but I'd leave that for IOCCC, not for a public api manual.
I hope that helps.
I find Berkeley to be a good product for what it was designed, but it has to many programming bad practices which force you to work with its manual right by your side, until you can hide it under an abstraction layer, and that's what I hate about Berkely.
Original published here.
Reading Berkeley's FM
Post by Nico Brailovsky @ 2010-03-26 | Permalink | Leave a comment
I got this from Oracle Berkely DB's FM:
skey->size = sizeof((struct student_record *)pdata->data)->last_name;
Take a good look at that pice of code:
a_number = sizeof((T*)pdata->data)->last_name;
Again:
a_number = sizeof(Whatever)->field;
Wait a minute. typeof(sizeof(x)) == const unsigned int. Right? So, again:
a_number = 42->field;
There's no way that first line can compile. Go and check it (in the example, not the last line please). I'll wait. Done? Yeap, I was surprised to, it does indeed compile. Mi first reaction towards this discovery went something like this:
What is going on there? It took me a while to figure out how evil Berkely 's manual can be. The answer next time.
In reply to this post, Nicolás Brailovsky » Blog Archive » Operator sizeof (AKA Reading Berkeley’s FM, take II) commented @ 2010-03-29T11:57:18.000+02:00:
[...] Last time I told you about an evil snipet I found on Oracle Berkeley DB’s manual: [...]
Original published here.
I hate Berkeley
Post by Nico Brailovsky @ 2010-03-25 | Permalink | Leave a comment
Polymorphism taken to 11:
| | |
| --- | --- |
| SQL Term | Oracle Berkeley DB Equivalent |
| Database | Environment |
| Table | Database |
| Tuple/row | Key/data pair |
| Secondary index | Secondary database |
WTF ORACLE, WTF.
In reply to this post, Gregory Burd commented @ 2010-03-25T15:40:48.000+01:00:
Hey Nicolás,
Sometimes we say the same thing about those names internally. :) WTF?! Well, first off the names were set in stone back in the early 1990s when Sleepycat was just formed, long long before we were acquired by Oracle. You have to look at how the product grew in complexity and scope over the years to fully understand the naming. We've talked a few times about fixing this, changing the API in drastic ways to make it more terminology-friendly. We didn't because we were trying not to break existing applications. So, here we are with somewhat odd naming and we admit that. :)
How'd you get my cartoon picture?!
cheers,
-greg Product Manager, Oracle Berkeley DB
Original published here.
In reply to this post, nico commented @ 2010-03-25T16:21:00.000+01:00:
Hi Greg!
As a maintainer of legacy applications I agree, changing the API now would be a nightmare, and it's understandable that those names may have made sense when they were chosen. It's a little bit weird but I guess we can live with that.
I have been working a little bit with Berkeley DB for a new project and there are some more posts on the queue about things I found odd during my first tests with it, like having a DB and a Db datatype or the usage of sizeof operator in the manual. Hope you like those posts too (I may borrow your cartoon picture again, some people say it does look a lot like me)
Original published here.
You know you're a geek...
Post by Nico Brailovsky @ 2010-03-23 | Permalink | Leave a comment
... when you try to log in to your homebanking account using admin:admin (*) (**)
(*) Alt take: a geek with weak passwords, yeah. My pin is 1234 and I'll never change it. (**) Replace homebanking with gmail, linkedin and $LATEST_NETWORKING_FAD and you're most likely mental. (***) (***) Replace mental with (*) to obtain a Moebious post.
/Delirious posting mode, deactivate!
Cofeeeeeee
Post by Nico Brailovsky @ 2010-03-18 | Permalink | Leave a comment
int main() {
otl_connect db;
otl_connect::otl_initialize();
db.rlogon("whatever");
int cuarentaydos;
const char *sql = "select 42 drom dual";
otl_stream stmt(1, sql, db);
if (!stmt.eof()) stmt >> cuarentaydos;
std::cout << "En la base 42 == " << cuarentaydos << "n";
db.logoff();
}
I spent half an hour looking for the error. How come drom is not a standard sql keyword? Damn!