![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
http://journal.stuffwithstuff.com/2010/10/21/the-language-i-wish-go-was/
An interesting look into some problems we've solved and why. (The fact that
it's phrased as "Go is missing this" isn't what's interesting.)
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> http://journal.stuffwithstuff.com/2010/10/21/the-language-i-wish-go-was/
I'm not so sure I agree with the necessity of 'union'.
'union' in C is basically a construct which exists to save some bytes
of memory in some rare circumstances. The price you pay for it is reduced
type safety: You always have to make sure you are using the object with
the correct type, or else you'll get garbage. More often than not, unions
are not used raw, but embedded in structs, where one of the struct members
tells the type of the union. While in some situations you can use this to
save memory (especially if you need to instantiate this struct millions of
times), it introduces the overhead of the type member and having to always
check it. (Without the union there would be no need to write any conditionals
based on the type.)
You could have the language always automatically check the proper type
of the union, but then you'll be having overhead on every single operation
you are doing with that union (overhead which could in many cases be avoided).
It would be rare for the memory saving advantage to be worth the overhead.
As for removing null pointers, that would present problems of its own.
Null pointers in languages like C, C++ and Java are often used for useful
things. For example if you have a linked list, a null 'next' pointer is
a good indication of the element being the last one in the list. Without
the possibility of having null pointers you would have to device some other
kind of solution.
In Objective-C you usually don't have to check for null pointers. You can
(usually) safely make method calls on objects even if the pointer is null
(in this case no method call will be done, and if the method has a return
value, the default value will be returned). This way you can do all kinds
of things without having to worry about null pointers. (Of course this
introduced a slight overhead on every method call, but method calls in
Objective-C are really heavy regardless, so the small null-pointer check
doesn't add significantly).
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New escreveu:
> http://journal.stuffwithstuff.com/2010/10/21/the-language-i-wish-go-was/
>
> An interesting look into some problems we've solved and why. (The fact
> that it's phrased as "Go is missing this" isn't what's interesting.)
I've read that before on reddit. Is that a co-worker or a pseudonym? :)
This kind of thing only happen to multilingual programmers: they are
always annoyed at the fact that their fav pet abstractions are scattered
among their favorite programming languages and either involve a
performance penalty or expressivity/flexibility penalty...
Guys who think all languages are the same and just choose the most
popular suffer from no such headaches... :p
--
a game sig: http://tinyurl.com/d3rxz9
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> 'union' in C is basically a construct which exists to save some bytes
> of memory in some rare circumstances.
I have also seen it used for typecasting, but nowadays I think casting the
address of the thing to the "wrong" pointer type and then indirecting it
gets used more. I.e.; { long x = ...; float f = *(float*)&x; }
> As for removing null pointers, that would present problems of its own.
> Null pointers in languages like C, C++ and Java are often used for useful
> things.
I think the way to think of it is that a pointer that can be null is a
different type than a pointer that can't be null, and you have to do the
equivalent of a dynamic_cast<> from a nullable pointer to a non-nullable
pointer before you can indirect thru it.
Of course, if your language wasn't lame, you'd be able to just say
if (x != null) y = *x;
and the compiler would use typestate or something to let that go, whereas
without the "if (x != null)" on the front, it would complain that maybe *x
is indirecting thru null.
The problem isn't that pointers might be null. The problem is that someone
might indirect thru a null (or otherwise uninitialized) pointer without
knowing it.
> In Objective-C you usually don't have to check for null pointers.
That's the other way to handle it. Or to throw an exception which you can
catch. The Obj-C way certainly sounds more ... PHPish. ;-)
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> Warp wrote:
> > 'union' in C is basically a construct which exists to save some bytes
> > of memory in some rare circumstances.
> I have also seen it used for typecasting, but nowadays I think casting the
> address of the thing to the "wrong" pointer type and then indirecting it
> gets used more. I.e.; { long x = ...; float f = *(float*)&x; }
The most clever use of 'union' I have seen was like this:
union Matrix4x4
{
double m[4][4];
struct
{
double m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44;
};
};
This means you can access the matrix like "transform.m[1][2] = 5;"
or like "transform.m23 = 5;";
Of course in this case this is just a trick to have two naming
conventions to access the same data (rather than to save memory).
> > In Objective-C you usually don't have to check for null pointers.
> That's the other way to handle it. Or to throw an exception which you can
> catch. The Obj-C way certainly sounds more ... PHPish. ;-)
It's actually really handy in Objective-C when developing for the iPhone.
You could have a member which points to some screen element, such as eg.
a label or an image, and you can write code which handles that element
(eg. hides/unhides it, or updates its text to show some info, and of course
when the owner dies, it has to release the object). However, when editing
the GUI of the program with Interface Builder, you can simply remove that
screen element without the program crashing due to a null pointer.
(There are exceptions to this, of course, ie. situations where a null
pointer is invalid and will cause eg. a 'invalid parameter' exception at
runtime, but in many situations null pointers will be quite "transparent".)
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 22/10/2010 05:33 PM, Warp wrote:
> I'm not so sure I agree with the necessity of 'union'.
>
> 'union' in C is basically a construct which exists to save some bytes
> of memory in some rare circumstances. The price you pay for it is reduced
> type safety: You always have to make sure you are using the object with
> the correct type, or else you'll get garbage. More often than not, unions
> are not used raw, but embedded in structs, where one of the struct members
> tells the type of the union. While in some situations you can use this to
> save memory (especially if you need to instantiate this struct millions of
> times), it introduces the overhead of the type member and having to always
> check it. (Without the union there would be no need to write any conditionals
> based on the type.)
>
> You could have the language always automatically check the proper type
> of the union, but then you'll be having overhead on every single operation
> you are doing with that union (overhead which could in many cases be avoided).
> It would be rare for the memory saving advantage to be worth the overhead.
You have just described Algebraic Data Types.
An ADT is basically like a (possibly singleton) union of (possibly
nullary) structs together with an enum that tells you which struct is
present at run-time.
If you just want a normal struct, you make an ADT with only one
constructor. If you just want an enum, you make an ADT with several
constructors each with zero fields. But an ADT generalises both, as you
can see.
Having to check which struct is present every single time you want to
access its fields _would_ be very annoying, except that this is where
Haskell's "pattern matching" comes in. With it, you can check which
struct is there and copy the field values into variables all in a single
operation. (It's a single primitive operation as far as Haskell is
concerned, although obviously the generated machine code is potentially
many instructions long.)
(I suppose it goes without saying that how all of this is actually
implemented isn't specified. But GHC does things like optimising away
constructor checks for singleton constructors, and making zero-field
constructors into static global constants, etc.)
> As for removing null pointers, that would present problems of its own.
> Null pointers in languages like C, C++ and Java are often used for useful
> things. For example if you have a linked list, a null 'next' pointer is
> a good indication of the element being the last one in the list. Without
> the possibility of having null pointers you would have to device some other
> kind of solution.
Again, Haskell does not allow null pointers. (Then again, Haskell really
deals with "references" rather than "pointers" as such.) This neatly
eliminates an entire class of bugs.
"But null pointers can be useful!" I hear you cry. For this, Haskell has
the "Maybe" type. Basically, if you say "Foo", it will definitely,
always, be a Foo. But if you say "Maybe Foo", then it may or may not be
a Foo - and the type system *requires* you to explicitly check whether
it's "null" or not before you do stuff to it.
In other words, pointers which can be null are distinguished from
pointers that cannot be null (in the type system). And you have to check
at run-time. (If you don't, your program just won't compile.)
Of course, Maybe is just a plain vanilla ADT, defined in plain vanilla
Haskell. It just happens to be part of the standard library.
I gather Eiffel did this, actually. But they retro-fitted it to the
language. So rather than saying "these [and only these] things might be
null", you get to say "these [and only these] things definitely will NOT
be null". Which is kinda backwards [compatible].
One thing null pointers are often used for are error conditions. Like,
you have a parser function that returns either a pointer to a parse
tree, or a null pointer if there was a parse error. In Haskell, another
ADT comes into play: it's called "Either". Instead of saying "this
returns a SyntaxTree", you say "this returns an Either ParseError
SyntaxTree". Meaning that it either returns a ParseError, or a
SyntaxTree. (And you have to explicitly check which one before you do
stuff to it.) Same deal as above, but you can return a _description_ of
the failure rather than just fail.
Apparently there are two kinds of programmers: The ones who look at all
of the above and go "wow, that's a whole lot of unecessary run-time
overhead!", and the ones who go "wow, that's really going to reduce the
amount of time I waste trying to debug my complex application"...
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Of course in this case this is just a trick to have two naming
> conventions to access the same data (rather than to save memory).
That's cool. FORTRAN had this too (a la "named DATA blocks", which is to say
what C would call "static" variables with names), and I'm pretty sure it was
there to save memory. Of course, that was back when 4K was a big machine.
> It's actually really handy in Objective-C when developing for the iPhone.
It's really handy in PHP too. ;-) Seriously, the "@" operator in PHP is all
kinds of convenient. It's basically a one-character way of saying
try { ... } catch {}. So { X = @yadda(this, that()); } means X gets an
empty string if either yadda or that throws an error, or "this" isn't
defined, or whatever.
As long as the convenience outweighs the problem you get when you didn't
*expect* the thing to be NULL, you're good. Phone app? Sure. Missile
launcher? Bad idea. :-)
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 22/10/2010 10:02 PM, Darren New wrote:
> As long as the convenience outweighs the problem you get when you didn't
> *expect* the thing to be NULL, you're good. Phone app? Sure. Missile
> launcher? Bad idea. :-)
Suddenly unsafePerformIO takes on a whole new meaning...
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 10/22/2010 2:02 PM, Darren New wrote:
>
> As long as the convenience outweighs the problem you get when you didn't
> *expect* the thing to be NULL, you're good. Phone app? Sure. Missile
> launcher? Bad idea. :-)
>
On a terrifyingly related note:
http://www.foo.be/docs/tpj/issues/vol2_1/tpj0201-0004.html
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Kevin Wampler wrote:
> On a terrifyingly related note:
> http://www.foo.be/docs/tpj/issues/vol2_1/tpj0201-0004.html
Excellent! That's a keeper.
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |