View mode: basic / threaded / horizontal-split · Log in · Help
May 12, 2008
Re: Safer casts
"Simen Kjaeraas" wrote
> On Sat, 10 May 2008 07:59:23 +0200, Janice Caron wrote:
>> 1) convert or downcast: cast(Foo)bar
>> 2) reinterpret: cast!(Foo)bar
>> 3) constancy: cast(invariant)bar, cast(!const)bar
>
> For 3), what if I want to cast const(int*) to const(int)*? 
> cast(const(int)*)cast(!const)foo?
>
> -- Simen

I'm not really joining this discussion (yet), but I just wanted to respond 
to this.

If the purpose of your cast is to assign to a const(int) * variable, you 
need no casts to do this.  const(int*) implicitly casts to const(int)*:

int m = 5;
const(int *) ptr = &m;
const(int)* ptr2 = ptr; // OK

Why?  Because I can't change anything through ptr2 that I couldn't change 
through ptr.

Now, if you casting to be able to rebind ptr, then I think you would need 
some crazy casting like you stated.

-Steve
May 12, 2008
Re: Safer casts
Janice Caron, el  9 de mayo a las 09:15 me escribiste:
> (*) Use RTTI to cast up and down the class heirarchy. In C++, this
> would be dynamic_cast<T>(x). For D, I suggest two things. Firstly, the
> cast:
> 
>     class!(T)(x)
> 
> to do that actual upcast or downcast - but RTTI dynamic casts can
> fail, so the question arises: What should we do if the cast fails?
> Should we return null, or should we throw an exception. My view is
> that we should throw an exception, but also introduce a new construct
> to test whether or not the cast would be possible in the first place:
> 
>     is!(T)(x)

I don't think it's a good idea, because you end up doing the RTTI check
twice this way. I think class!(T)(x) (I don't like the name but that's
another issue) should return null in case of failure. If you want it to
throw an exception, just wrap it with enforce[1]:

   enforce!(class!(T)(x))

This have been discussed recently, but this way it's more efficient (and I
think more clear and less typing):

   void f(A a)
   {
       if (B b = class!(B)(a))
       {
           /*...*/
       }
       else if (C c = class!(C)(a))
       {
           /*...*/
       }
   }

[1] http://www.digitalmars.com/d/2.0/phobos/std_contracts.html

> (*) Reinterpret a bit pattern. In C++, this would be
> reinterpret_cast<T>(x). Without changing the memory layout, or the
> constancy, reinterpret the bits to mean something else. For D, I
> suggest
> 
>     union!(T)(x)
> 
> 
> (*) Change const to mutable, or invariant to mutable. In C++, this
> would be const_cast<T>(x). There is no equivalent in D, however, in D,
> one can currently write cast(T)x, and constancy will be magically (and
> dangerously) waved away. In the new scheme, I suggest:
> 
>     auto!(T)(x)

I think this 2 can be merged toguether and called horrible_cast in honour
to Don Clugston's "Member Function Pointers and the Fastest Possible C++
Delegates" article [2] =)

[2] http://www.codeproject.com/KB/cpp/FastDelegate.aspx

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
For me to ask a woman out, I've got to get into a mental state like the karate
guys before they break the bricks.
	-- George Constanza
May 12, 2008
Re: Safer casts
Janice Caron, el 11 de mayo a las 12:53 me escribiste:
> On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
> >  also, what if a doesn't actually have a "member" member? this is still
> >  syntactically valid D code, but again I think the error would be
> >  reported elsewhere.
> 
> On that point, I concede. The reporting of template errors could
> certainly be improved. More than once I have wanted to see the "stack
> trace" of errors, working back from the innermost, to the line of code
> that ultimately triggered it.
> 
> However, that it not an argument against templates, it is an argument
> for improved error reporting. And hopefully, one day we'll get that.
> 
> This is not the first time that you've argued that some feature or
> strategy is bad because today's D compiler isn't good enough, but you
> need to remember that tomorrow's D compiler will be better. That's
> life on the cutting edge.

I think you can use Token Strings[1] in D2 to have better error reporting.
It justs do lexical analisys, but it's something:

sort!(q{a > b})(array);

[1] http://www.digitalmars.com/d/2.0/lex.html

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
Señor, usted es militar? - No, no.
Tiene un hermano militar? - No, no, no.
Tiene algún pariente militar? - No, no, no, no.
Tiene algún amigo íntimo militar? - No, no, pero por qué me lo pregunta?
Porque me está pisando el pie.
	-- Tato vs. Tato (1980, Gobierno de Videla)
May 12, 2008
Re: Safer casts
Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> Now, if you casting to be able to rebind ptr, then I think you would need
> some crazy casting like you stated.
>
> -Steve

Actually, I had no other intent than to see if I could break the system.
For a better (or worse, mayhaps) version: const(C*)* (or whatever, really)
to const(invariant(C)*)*. For this, I'd prefer Janice's suggestion of
const cast, as I understand it:

  const(C*)* foo;

  cast(const(invariant(C)*)*)foo; // error, cast can't change constancy

  const cast(const(invariant(C)*)*)foo; // works like a charm

The const cast looks good to me, whereas what I used in the last example
was downright ugly. Casting to a different constancy should be one cast,
not first making it all mutable, and then put const back in there.

-- Simen
May 12, 2008
Re: Safer casts
Leandro Lucarella wrote:
> Janice Caron, el 11 de mayo a las 12:53 me escribiste:
>> On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>>>  also, what if a doesn't actually have a "member" member? this is still
>>>  syntactically valid D code, but again I think the error would be
>>>  reported elsewhere.
>> On that point, I concede. The reporting of template errors could
>> certainly be improved. More than once I have wanted to see the "stack
>> trace" of errors, working back from the innermost, to the line of code
>> that ultimately triggered it.
>>
>> However, that it not an argument against templates, it is an argument
>> for improved error reporting. And hopefully, one day we'll get that.
>>
>> This is not the first time that you've argued that some feature or
>> strategy is bad because today's D compiler isn't good enough, but you
>> need to remember that tomorrow's D compiler will be better. That's
>> life on the cutting edge.
> 
> I think you can use Token Strings[1] in D2 to have better error reporting.
> It justs do lexical analisys, but it's something:
> 
> sort!(q{a > b})(array);
> 
> [1] http://www.digitalmars.com/d/2.0/lex.html
> 
this was already debated thoroughly, But I'll state my POV again. I
don't like the use of strings here at all. in any form.
D is a strongly typed language which I like and all those string tricks
although cool are bad IMO.

my issues with the use of this syntax:
a) what if I had a typo? what if i typed n instead of b (they are next
to each other on my keyboard)? your solution or any other string
solution cannot check this, since it is syntactically valid D code
inside the string.
b) if I want to compare q{a.member > b.member} there is no check that
member exists, or any other type checking. the error would occur in the
template code itself not in the string in both of the above examples.
c) what if I forgot to type the "q"?
d) most IDEs mark strings with a different color or something like that
so I treat them automatically as data and not code. ( this is a minor
issue, since IDEs could be made to work differently. but, my
sub-conscience response to strings as "not code" is harder to fix)

the only benefit to this is a slight performance benefit (though a good
compiler could provide the same performance by inlining a function call)
and a slightly shorter syntax which is a personal preference since you
type less but IMHO it becomes less readable and less obvious.
I prefer:
sort!((int a, int b) {return a.member > b.member;})(array);
this is more typing but provides all the checks and is more readable.
Think of the poor guy that will need to do maintenance on your code
years from now. now the string is a cool quick'n'dirty solution to the
problem at hand but in the future that other programmer will have no
idea what those "a" and "b" are. especially since you didn't write the
types of them.
also the performance could be the same if I used a function instead of a
delegate allowing the compiler to inline it (hopefully).

since this is identical to:
sort(array, (int a, int b) {return a.member > b.member;});
there is no benefit in making it a template, IMO.

side note: using a feature of arrays in D this could be also rewritten as:
array.sort((int a, int b) {return a.member > b.member;});

Again, this is only my opinion (and I do prefer higher level solutions
and think the compler/linker can do a better job optimizing than I can).
you do not have to agree with this view, and there are already people
that disagree.
May 12, 2008
Re: Safer casts
On 12/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>  I prefer:
>  sort!((int a, int b) {return a.member > b.member;})(array);

ints don't have a member variable called .member, so presumably, you
must have meant something like

   class C { int member; }
   C[] array;
   sort!(C a, C b){return a.member > b.member;})(array);


>  this is ... more readable.

No it isn't. ;-)


>  but in the future that other programmer will have no
>  idea what those "a" and "b" are. especially since you didn't write the
>  types of them.

Incorrect. "a" and "b" are the placeholders for the things being
compared. This is well documented in the documentation for sort. The
only way anyone could not know what the "a" and "b" were would be if
they hadn't RTFM.

The type of a is the type of the array element. This is obvious.



>  there is no benefit in making it a template, IMO.

The benefit is choice.
May 12, 2008
Re: Safer casts
Yigal Chripun Wrote:

> my issues with the use of this syntax:
> a) what if I had a typo?

algorithm.d(2528): Error: binaryFun(ElementType1,ElementType2) is not an lvalue
algorithm.d(2528): static assert  "void*"

Maybe the static assert message should be better. What if it says: Your comparison function is invalid? 

> what if i typed n instead of b (they are next
> to each other on my keyboard)?

Same message is written.

> your solution or any other string
> solution cannot check this, since it is syntactically valid D code
> inside the string.
> b) if I want to compare q{a.member > b.member} there is no check that
> member exists, or any other type checking. the error would occur in the
> template code itself not in the string in both of the above examples.

Same message is written again.

> c) what if I forgot to type the "q"?

./test.d(9): found '}' when expecting ';' following 'statement'

At least now it is in your file ^_^

> d) most IDEs mark strings with a different color or something like that
> so I treat them automatically as data and not code. ( this is a minor
> issue, since IDEs could be made to work differently. but, my
> sub-conscience response to strings as "not code" is harder to fix)

The strings are short otherwise they anyway are better as functions. I do not think this could be a problem.

> the only benefit to this is a slight performance benefit (though a good
> compiler could provide the same performance by inlining a function call)
> and a slightly shorter syntax which is a personal preference since you
> type less but IMHO it becomes less readable and less obvious.

I think it is very readable and obvious for reasons below.

> I prefer:
> sort!((int a, int b) {return a.member > b.member;})(array);
> this is more typing but provides all the checks and is more readable.

It is nice you can do both. You can put a string when it is small. You double the size of the code to write. When you have long comparison, you make it separate function. What I think is best of D when coming from other languages is that it gives so much options in such small core. 

> Think of the poor guy that will need to do maintenance on your code
> years from now. now the string is a cool quick'n'dirty solution to the
> problem at hand but in the future that other programmer will have no
> idea what those "a" and "b" are. especially since you didn't write the
> types of them.

Here you may be wrong two times. First I tell from experience. I worked internship for a biotech company in Boston. I thought it will be research but it was so much work! ^_^ They used Perl and I did not know Perl when I began. But then I learned it and it has many nice things. One is sort which looks like this

sort { $a <=> $b } array;

I remember: first time I saw sort I understood how it works. The only odd thing was <=> but that means -1, 0 or 1 if a is less, equal or greater than b. I thought Perl has the most elegant definition of sort but now I think D has it.

Second you may be wrong because you think types help. They do not help in fact they may un-help. Write this

long array[] = ...;
sort!((int a, int b) {return a > b;})(array);

Sadly D lets long -> int conversion go through. Code will compile and run! But it gives wrong results for big numbers.

For sort type deduction is best. You should write

sort!((auto a, auto b) {return a > b;})(array);

And that works with int, long, float, string and all types that have >. It is the best writing of the intent of the sort. But I do not know how much type inference the D compiler can do.

> also the performance could be the same if I used a function instead of a
> delegate allowing the compiler to inline it (hopefully).

Good abstraction is the best. Performance is a good bonus ^_^

> since this is identical to:
> sort(array, (int a, int b) {return a.member > b.member;});
> there is no benefit in making it a template, IMO.

I hoped I convinced you otherwise. After all effort still no understanding? Templates are best. They give you static and dynamic. Dynamic only gives dynamic.

> side note: using a feature of arrays in D this could be also rewritten as:
> array.sort((int a, int b) {return a.member > b.member;});

Would be nice to allow array.sort!(cmp).

> Again, this is only my opinion (and I do prefer higher level solutions
> and think the compler/linker can do a better job optimizing than I can).
> you do not have to agree with this view, and there are already people
> that disagree.

Different views of same issues is good. But I see there are some things about which you are simply wrong because you do not understand how they work. Then I waste time explaining ^_^ Thank you, Dee Girl
May 12, 2008
Re: Safer casts
Yigal Chripun wrote:
> Leandro Lucarella wrote:
>> Janice Caron, el 11 de mayo a las 12:53 me escribiste:
>>> On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>>>>  also, what if a doesn't actually have a "member" member? this is still
>>>>  syntactically valid D code, but again I think the error would be
>>>>  reported elsewhere.
>>> On that point, I concede. The reporting of template errors could
>>> certainly be improved. More than once I have wanted to see the "stack
>>> trace" of errors, working back from the innermost, to the line of code
>>> that ultimately triggered it.
>>>
>>> However, that it not an argument against templates, it is an argument
>>> for improved error reporting. And hopefully, one day we'll get that.
>>>
>>> This is not the first time that you've argued that some feature or
>>> strategy is bad because today's D compiler isn't good enough, but you
>>> need to remember that tomorrow's D compiler will be better. That's
>>> life on the cutting edge.
>> I think you can use Token Strings[1] in D2 to have better error reporting.
>> It justs do lexical analisys, but it's something:
>>
>> sort!(q{a > b})(array);
>>
>> [1] http://www.digitalmars.com/d/2.0/lex.html
>>
> this was already debated thoroughly, But I'll state my POV again. I
> don't like the use of strings here at all. in any form.
> D is a strongly typed language which I like and all those string tricks
> although cool are bad IMO.
> 
> my issues with the use of this syntax:
> a) what if I had a typo? what if i typed n instead of b (they are next
> to each other on my keyboard)? your solution or any other string
> solution cannot check this, since it is syntactically valid D code
> inside the string.
> b) if I want to compare q{a.member > b.member} there is no check that
> member exists, or any other type checking. the error would occur in the
> template code itself not in the string in both of the above examples.
> c) what if I forgot to type the "q"?

All of these things will cause compile-time errors.  You are right that 
the error reported may not point to the actual mistake in a very clear 
way, but you will get a syntax error right away.

The string gets turned into code via mixin(the_string) so if anything is 
not right with the code in the string, the compiler will barf.  Maybe 
you were thinking it was doing some sort of parsing of the string to 
generate a comparison function for you?  No. Just a raw mixin() in a 
scope in which 'a' and 'b' have been aliased to be the two elements 
being compared.

> d) most IDEs mark strings with a different color or something like that
> so I treat them automatically as data and not code. ( this is a minor
> issue, since IDEs could be made to work differently. but, my
> sub-conscience response to strings as "not code" is harder to fix)

The q{foo} thing was taken from Perl, so any IDE that can highlight perl 
should be able to highlight this in D with some tweaks.

--bb
May 12, 2008
Re: Safer casts
Janice Caron wrote:
> On 12/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>>  I prefer:
>>  sort!((int a, int b) {return a.member > b.member;})(array);
> 
> ints don't have a member variable called .member, so presumably, you
> must have meant something like
> 
>     class C { int member; }
>     C[] array;
>     sort!(C a, C b){return a.member > b.member;})(array);
> 
right. Thanks for the fix. I'm not that good with examples.
> 
>>  this is ... more readable.
> 
> No it isn't. ;-)
> 
> 
>>  but in the future that other programmer will have no
>>  idea what those "a" and "b" are. especially since you didn't write the
>>  types of them.
> 
> Incorrect. "a" and "b" are the placeholders for the things being
> compared. This is well documented in the documentation for sort. The
> only way anyone could not know what the "a" and "b" were would be if
> they hadn't RTFM.
> 
> The type of a is the type of the array element. This is obvious.
> 
again, obvious to you, not that dude five years from now reading your
code. documented is not the same as compiler checked, and we both know
that documentation could get out of sync with the code.
also, why do I have to go and search the docs if the code is in front of me?
at my work we have a very large code base in Fortran, which has to be
linked to every program. I don't know Fortran and don't need to since I
use c++. all those things there that where so obvious to the Fortran
coders 15 years ago look to me like raw binary code. they've used
various low-level tricks that no one understands and that aren't
properly documented. if I get a linking error with those Fortran objects
I could spend days trying to figure it out. I can look at the code and
try to understand what's going on, but I don't know Fortran so every bit
of readability helps. replace Fortran with D in this (real life) example
and try to understand that it's not so easy as you make it.
> 
> 
>>  there is no benefit in making it a template, IMO.
> 
> The benefit is choice.

choice of what? You've said so yourself, both templated and
non-templated versions of the sort-with-delegate are identical.
you want those string templates (which i don't like) than fine, define
them as templates and i won't use them. but the version with the
delegate is needlessly a template.

I guess I wouldn't object as much if D's syntax for calling templated
code weren't different from regular functions which would bring a more
uniform syntax (take a look at macros in Nemerle).
Does it irritate only me? maybe I am the odd one here. I just don't want
to care if one array function is a generic template, while another
isn't. ideally (not possible in current D) both forms should have the
same syntax, so the end user (me) doesn't need to know nor care about
what sort of implementation was chosen.
May 12, 2008
Re: Safer casts
Somebody please throw Yigal's towel before Janice and the karate girl beat him into a pulp. Going by his responses he has an eye closed already.
7 8 9 10 11 12 13 14 15
Top | Discussion index | About this forum | D home