www.digitalmars.com         C & C++   DMDScript  

D - Concrete Types/Argument Passing

reply "Rui Ferreira" <t5rui hotmail.com> writes:
Interesting language spec. Property fields and the super() constructor
scheme are two things that should have been in c++ for a long time now.

But I'm wondering, what is D's support for concrete classes. I can see
structs are supported but are member functions allowed on them ? What about
derivation of concrete classes, is there any ?

Do not underestimate the need for concrete classes. I can see some threads
on operator overloading but if you think about it the real benefit for such
sugary comes precisely from the use of concrete classes to model small
conceptual models.

Class trees are a totally different beast to me. If in D every function is
virtual by default, do I need to use a vtable for a vector3f class ? That
sounds overkill, a simple struct would do. But C structs aren't as
expressive as a c++ non virtual class can be. It lacks members functions and
operator overloading.

I like to see that function arguments semantics are clean for once. The
'const' keyword usage on c++ is mostly a cancer, born from the need to apply
read permissions to arguments, so we can pass large enough objects without
performance degradation and the assurance it will not change value. Quite
the hack.

The 'in', 'out' and 'inout' keyword are just the right way to do the
argument passing, but what do these keywords mean when applied to a struct ?
Does this mean structs are ALWAYS by value by default ? That also sounds
overkill. I've always thought that this should be addressed by the language
itself.

Compilers, and Visual Studio in particular is keen to make a memcpy of a
struct passed by value if it is more than 4 words long, if not, it will use
the registers to do the grunt work. Now, for me this is the key point to be
on the lookout to decide if a class should be passed by value or by
reference. Most of the time there is no need to change the value, this is
the most useful and frequent usage of an argument, if there is a need then
it will act as a local variable. Maybe that can happen to an int or two that
goes into a for loop, but not needed on most of the concrete "types" I
know -- They really shouldn't be called classes.

So I think this should be taken into account by the compiler itself. If a
copy is expensive for any given argument the compiler will use by reference
passing to optimize the access if and only if the argument IS ONLY USED ON
CONST SEMANTICS, that is if the function does not change the argument then
the implementation can use a pointer safely to make an efficient 'in'
argument. If the function does change the value, then it will use the copy
by value instead to preserve local usage.

Another solution : Perhaps change to 'in' values shouldn't be allowed at all
and the user should be forced to copy to local variables if there is any
need to use a temporary storage for 'in' arguments. This doesn't sound
impressively limited to me and it can probably be considered good code
design.

Standard classes will be passed by reference as always. OOP demands it, they
are not stack objects at all. But concrete types are.... they are different.
It would be a good thing to divide and enforce these two concepts
separately.

Maybe we can have class {} with all the wonders of vtables, and type {} or
an enhanced struct {} to handle all the necessities of a good concrete type.
Operator overloading only makes good sense on them, so maybe they should be
banned from standard classes altogether and take advantage of the vtable
absence to implement some serious operator overloading like handle multiple
sums of vector the correct way or to avoid spurious temporaries.

This would be indeed a language I would like to code in.

-Rui Ferreira
Sep 03 2001
next sibling parent reply Axel Kittenberger <axel dtone.org> writes:
Thats the reason why I in example decided -not- to use 'in', 'out' and 
'thru'. What does 'in' to an object type mean? can we change it fields? 
Does the caller feel that? Can we members of the object that change it 
fields? Okay on an 'out' we can change the "pointer" to the class itself 
and the callers also receives a new pointer, but actually there are many 
different levels between in and out. 100% reference the callee can change 
the actual value of it, in the next 'itermediate' level it can change the 
fields of the object, but not the pointer to itself, and then the lowest 
level with 'const' in C++ grammar it can neither change the object nor the 
pointer to it. How does this fit to 'in', 'out', 'thru'?

Okay there are even more finer access levels if you've an an array of 
objects. The whole array root pointer itself may be changed, the content 
pointers of the  array may be changed, only the object fields may be 
changed, nothing at all may be changed.

A lot of people writing userspace applications on pc's, say let's scrap 
that const, or simply don't bother using it correctly. However on embedded 
systems you're always lurking to put as much into ROM instead of RAM as 
possible, and that means 'const'. Beside normal programmer idioty security 
correct const decleartations provides a lot of hints for the optimizer, so 
(ofcourse in my personal impression only) leaving it away or not handling 
it correctly is reducing yourself from to professional programming language 
to a teaching language for scools, or as better script language.   

- Axel
Sep 03 2001
parent "Walter" <walter digitalmars.com> writes:
Axel Kittenberger wrote in message <9n015m$1h3u$1 digitaldaemon.com>...
Beside normal programmer idioty security
correct const decleartations provides a lot of hints for the optimizer, so
(ofcourse in my personal impression only) leaving it away or not handling
it correctly is reducing yourself from to professional programming language
to a teaching language for scools, or as better script language.
In actual practice, const doesn't help the optimizer much. Too many programs cast away const, plus some other subtleties of it, conspire to make it worthless. Hence, in D, const is not a type modifier, but a storage class. A const storage class means the declarations in it can be put in ROM, the compiler can fold multiple instances together, and the compiler can do constant folding on them.
Sep 03 2001
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
Rui Ferreira wrote in message <9mvvkn$1gd8$1 digitaldaemon.com>...
But I'm wondering, what is D's support for concrete classes. I can see
structs are supported but are member functions allowed on them ?
No. Structs are simply C'ish aggregations.
 What about
derivation of concrete classes, is there any ?
What's a "concrete" class?
Class trees are a totally different beast to me. If in D every function is
virtual by default, do I need to use a vtable for a vector3f class ? That
sounds overkill, a simple struct would do. But C structs aren't as
expressive as a c++ non virtual class can be. It lacks members functions
and
operator overloading.
The vtable overhead is slight, and I think a reasonable tradeoff.
I like to see that function arguments semantics are clean for once. The
'const' keyword usage on c++ is mostly a cancer, born from the need to
apply
read permissions to arguments, so we can pass large enough objects without
performance degradation and the assurance it will not change value. Quite
the hack.
D gets rid of "const" as part of the typing system, although you can still declare constants.
The 'in', 'out' and 'inout' keyword are just the right way to do the
argument passing, but what do these keywords mean when applied to a struct
?
Does this mean structs are ALWAYS by value by default ? That also sounds
overkill. I've always thought that this should be addressed by the language
itself.
Structs are by value, and classes are by reference. 'out' and 'inout' parameters are always passed by reference.
Sep 03 2001
next sibling parent reply Axel Kittenberger <axel dtone.org> writes:
 What's a "concrete" class?
When I understood corectly he means classes that are normally handled like they would be aggregate type, 'Point' would be a classic example, in graphic code the Point class is often used in a way it feels as it just a normal primitive datatype.
 The vtable overhead is slight, and I think a reasonable tradeoff.
So you're defintly targeting to be a userspace application only? In my eyes these tougher uses like emmbeded (os-less) applications or kernelspace were the main benefit the industry saw in C over Pascal (in the 90ies) and led over the years to displacement of Pascal also in userspace, but well this of course a subjective view only.
 D gets rid of "const" as part of the typing system, although you can still
 declare constants.
but not constant strings, or? I'm a little confused, say a function takes 'char *' as in parameter, 'in' on arrays mean we cannot change it's values it would be 'const char *' in C speak. Okay so array I want to modify are 'out' so it would be normal 'char *' in C speak. Now how do I secify a function which returns a pointer to an string as out parameter? Like strtol() in example. It might just be that I did not understand things correctly as I never used Eiffel or where the in/out/thru paradigm came frome. Hmmm, could you maybe point out how in in/out/inout way following classical C functions would be coded? size_t strlen(const char *s); char *strcpy(char *dest, const char *src); long int strtol(const char *nptr, char **endptr, int base); I think these examples suite well to be a pretty universal answer :o) (well for arrays at least) - Axel
Sep 03 2001
parent reply "Walter" <walter digitalmars.com> writes:
Axel Kittenberger wrote in message <9n0n3a$1v21$1 digitaldaemon.com>...
So you're defintly targeting to be a userspace application only?
I don't understand why you conclude that from structs not having vtables and classes having.
but not constant strings, or?
Sure: const char*p = "hello";
 I'm a little confused, say a function takes
'char *' as in parameter, 'in' on arrays mean we cannot change it's values it would be 'const char *' in C speak. Not really. The in only applies to what is passed on the stack, which would be the pointer, not the data.
 Okay so array I want to modify are
'out' so it would be normal 'char *' in C speak. Now how do I secify a function which returns a pointer to an string as out parameter? Like strtol() in example. void func(out char* foo);
Hmmm, could you maybe point out how in in/out/inout way following
classical C functions would be coded? size_t strlen(const char *s); char *strcpy(char *dest, const char *src); long int strtol(const char *nptr, char **endptr, int base); I think these examples suite well to be a pretty universal answer :o) (well for arrays at least) size_t strlen(char* s); char* strcpy(char* dest, char* src); int strtol(char* nptr, out char* endptr, in int base);
Sep 03 2001
next sibling parent reply Axel Kittenberger <axel dtone.org> writes:
 size_t strlen(char* s);
 char* strcpy(char* dest, char* src);
Okay then there is nothing that checks for const violations? like mismatched arguments will result for you into a runtime segfault: char *foo; strcpy("hallo", foo); from where a normal C comiler is perfectly able to warn/error for. - Axel
Sep 03 2001
parent reply "Walter" <walter digitalmars.com> writes:
Correct. Const is not part of the typing system, although you will get an
error if you try storing directly into a const:

    const int foo = 5;
    foo = 3;        // error

Note that C hardly gets it right. Look at strchr().

 -Walter

Axel Kittenberger wrote in message <9n1pt5$2iqm$2 digitaldaemon.com>...
 size_t strlen(char* s);
 char* strcpy(char* dest, char* src);
Okay then there is nothing that checks for const violations? like mismatched arguments will result for you into a runtime segfault: char *foo; strcpy("hallo", foo); from where a normal C comiler is perfectly able to warn/error for. - Axel
Sep 05 2001
next sibling parent reply Axel Kittenberger <axel dtone.org> writes:
 Note that C hardly gets it right. Look at strchr().
Indeed! I never noticed that. Now I finally know how I make 'secret' const casts, that pass through altough the compilers has const-cast-warnings truned on and is set on stop on warning :o) But the problem is not easy to solve :/ Adding const at the return value is false too, people using strchr() on a really changeable array also want to have a changeable return pointer. Hmmm don't know would 'const' overloadable within C++? Or also for c++ could a template fix this? (Fortunally) I never deeped that far into C++.
 Correct. Const is not part of the typing system, although you will get an
 error if you try storing directly into a const:
 
     const int foo = 5;
     foo = 3;        // error
Hmm I start to understand a bit, so I guess a call to an function declaring this one as 'out' would also not be allowed right? But I still don't want to totally abandon the const's paradigm, from the practice I expirienced that adding the correct const attributes to a project usually spots bugs even before they ever appeared for the user, or using the correctly from start of hinders a whole set of programming failures even before they arise, even if it didn't help the optimizer at all. I agree that 'const' in C++ is very confusing, especially in conjuction with typedefs, with type const struct members against const applied to the whole struct. And then when discussing with others it's funny that a set of people programming C fulltime for a couple years, still can't say certainly how more complicates constructions with const work out. - Axel
Sep 06 2001
parent "Walter" <walter digitalmars.com> writes:
Axel Kittenberger wrote in message <9n8if5$7rh$1 digitaldaemon.com>...
And then when discussing with others it's funny that a set of
people programming C fulltime for a couple years, still can't say certainly
how more complicates constructions with const work out.
Even worse, const doesn't help the optimizer anyway, because some other non-const pointer may point to the same data and change it. Const just doesn't work as a type attribute.
Sep 07 2001
prev sibling parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Walter wrote:
 
 Correct. Const is not part of the typing system, although you will get an
 error if you try storing directly into a const:
 
     const int foo = 5;
     foo = 3;        // error
 
 Note that C hardly gets it right. Look at strchr().
What's wrong with strchr()? MSVC's version of it seems to be declared sanely. -RB
Sep 07 2001
next sibling parent reply Axel Kittenberger <axel dtone.org> writes:
Russell Bornschlegel wrote:

 Walter wrote:
 
 Correct. Const is not part of the typing system, although you will get an
 error if you try storing directly into a const:
 
     const int foo = 5;
     foo = 3;        // error
 
 Note that C hardly gets it right. Look at strchr().
What's wrong with strchr()? MSVC's version of it seems to be declared sanely.
*must hold back scarcasm* *must hold back scarcasm*
Sep 07 2001
parent reply Axel Kittenberger <axel dtone.org> writes:
 What's wrong with strchr()? MSVC's version of it seems to be
 declared sanely.
*must hold back scarcasm* *must hold back scarcasm*
Ooops sorry I hit enter too early, I was still in typing the message... so don't take it personally :/ MSVC's version just as good/bad as every others. Take a look what strchr() takes for an argument and take a look what the return type is. So what happened to the 'const'? If I've a 'const char *' so am not allowed to change it, and search for a character with strchr(), it returns: suprise a 'char *' pointer, one that I can use to modify the contents from which was before forbidden. . Axel
Sep 07 2001
parent Russell Bornschlegel <kaleja estarcion.com> writes:
Axel Kittenberger wrote:
 
 What's wrong with strchr()? MSVC's version of it seems to be
 declared sanely.
*must hold back scarcasm* *must hold back scarcasm*
Ooops sorry I hit enter too early, I was still in typing the message... so don't take it personally :/ MSVC's version just as good/bad as every others. Take a look what strchr() takes for an argument and take a look what the return type is. So what happened to the 'const'? If I've a 'const char *' so am not allowed to change it, and search for a character with strchr(), it returns: suprise a 'char *' pointer, one that I can use to modify the contents from which was before forbidden.
Got it. Thanks. -RB
Sep 07 2001
prev sibling parent "Walter" <walter digitalmars.com> writes:
Russell Bornschlegel wrote in message <3B990579.49549F81 estarcion.com>...
Walter wrote:
 Correct. Const is not part of the typing system, although you will get an
 error if you try storing directly into a const:

     const int foo = 5;
     foo = 3;        // error

 Note that C hardly gets it right. Look at strchr().
What's wrong with strchr()? MSVC's version of it seems to be declared sanely.
strchr() implicitly converts a const char * into a char *.
Sep 08 2001
prev sibling parent Axel Kittenberger <axel dtone.org> writes:
 Axel Kittenberger wrote in message <9n0n3a$1v21$1 digitaldaemon.com>...
So you're defintly targeting to be a userspace application only?
I don't understand why you conclude that from structs not having vtables and classes having.
Oh sorry, I misunderstood it as you're forcing always to use virtual functions on classes, no 'final' allowed. - Axel
Sep 05 2001
prev sibling next sibling parent reply Dan Hursh <hursh infonet.isl.net> writes:
Walter wrote:
 
 Rui Ferreira wrote in message <9mvvkn$1gd8$1 digitaldaemon.com>...
But I'm wondering, what is D's support for concrete classes. I can see
structs are supported but are member functions allowed on them ?
No. Structs are simply C'ish aggregations.
 What about
derivation of concrete classes, is there any ?
What's a "concrete" class?
From Stroustrup's "The C++ Programming Language" The intention of a concrete type is to do a single, relatively small thing well and efficiently. It is not usually the aim to provide the user with facilities to modify the behavior of a concrete type. In particular, concrete type are not intended to display polymorphic behavior. If you don't like some detail of a concrete type, you build a new one with the desired behavior. If you want to "reuse" a concrete type, you use it in the implementation of your new type exactly as you would have used an int. He gives a number of examples elsewhere in the book of concrete type like date, vector, BCD characters, (value, unit) pairs, scaled fixed point number, etc. I've always consider concrete type to be one of those things taught as a discipline, but not really anything you gave thought to. I'm glad Rui spoke up! I never considered this. Perhaps, if D could support a form of concrete type, it could control the abuse of overloads. It would also help cut down on virtual calls when they are truly over kill. How about this? 1) Concrete types are a form of data aggregation like a C structs, but with methods associated. (I would like to say they can be passed in place of C structs to make writing OpenGL wrappers a little friendlier. Would that be too difficult?) 2) They can be declared locally. 3) They cannot be inherited from. They cannot inherit from other types. There is nothing polymorphic about them, hence method are not virtual. 4) They can have constructors and a destructor. There is no guarantee that the destructor will be run immediately when a variable goes out of scope, but it will be run. (I don't want to go to the extreme of saying they can't allocate resources.) 5) I think we might want to say they can have private/public style protection on members, since you probably would want people messing with the internal of some Date implementations. The same might be true of other types. 6) They are the only user defined types that support any form of operator overloading. (This is assuming that we can find a form of operator overloading that isn't too much trouble.) It would help in library implementations of simple types, and it would allow user defined vector math type that will be useful in tight loops. I care about that. :-) I do think it could lead to a useful, safe compromise. It could also make for a nicer standard library. I'm not sure if there should be any consideration with regard to potential problems with generic programming (templates), if D ever supports something like that. Also, some folks might want to see a way to interface such types with switch. Since we probably won't have a way to declare literal, this is probably unreasonable. I do know that I don't like concrete as a keyword. We'd need a better name for it. I think it should be usable anywhere a struct is, but I get the gut feeling that it should be separate from a struct, but I don't have a good reason for that. Thoughts? Dan
Sep 03 2001
parent reply "Rui Ferreira" <t5rui hotmail.com> writes:
 I've always consider concrete type to be one of those things taught as a
discipline, but not really anything you gave thought to. Perhaps if you are only using Struct as a means of implementation to an interface you should forgo discipline. In fact, come to think of it, I think this is Walter's reasoning behind the current C Structs usage. The thing is that concrete types are much more than an implementation detail -- although they can be, and with organized results. They are more usefully used directly, exposing their public interface to provide a memory block on the form of a data model.
 3)  They cannot be inherited from
Well, I have found some uses to inheritance, here it mostly serves the purpose of code reuse. A pragmatic role I guess, but not terribly important.
 They can have constructors and a destructor.  There is no guarantee that
the destructor will be run immediately when a >>variable goes out of scope, but it will be run. (I don't want to go to the extreme of saying they can't allocate >>resources.) Yes, perhaps we can make some compromises regarding c++ here. A destructor is generally used on a concrete type to provide the "resource acquisition is initialization" paradigm. I am used to this, so I'm biased, but we may find a better alternative. I am not experienced enough to know if the 'finally' clause is a good one, but the auto-magical properties of a local concrete "handle" that releases its resources at the end of a block are very alluring. --- Regarding the rest, data hiding with protection keywords is a must, and yes, operator overloading only on these types of data structures is a very good "force the users to use it" design compromise.
and it would allow user defined vector math type that will be useful in
tight loops. And you know we need them... :] -Rui Ferreira
Sep 04 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
Rui Ferreira wrote:
 3)  They cannot be inherited from
Well, I have found some uses to inheritance, here it mostly serves the purpose of code reuse. A pragmatic role I guess, but not terribly important.
I was just going on Bjarne's description. To reuse them you make them a member. I do believe that we ought to prohibit virtual methods and polymorphism, but I guess I don't have a good reason for that.
 They can have constructors and a destructor.  There is no guarantee that
the destructor will be run immediately when a >>variable goes out of scope, but it will be run. (I don't want to go to the extreme of saying they can't allocate >>resources.) Yes, perhaps we can make some compromises regarding c++ here. A destructor is generally used on a concrete type to provide the "resource acquisition is initialization" paradigm. I am used to this, so I'm biased, but we may find a better alternative. I am not experienced enough to know if the 'finally' clause is a good one, but the auto-magical properties of a local concrete "handle" that releases its resources at the end of a block are very alluring.
I like that style of resource management to, but it's a little rough because of garbage collection from what I hear. Beside, I think the finally statement is supposed to be "the D way" of do this. I guess I will probably grow to like it since I would have to create an entire class just to get the same results.
 Regarding the rest, data hiding with protection keywords is a must, and yes,
 operator overloading only on these types of data structures is a very good
 "force the users to use it" design compromise.
There is a strong element against overloading on this group though. I don't want to presume that there will be overloading. But limiting them to concrete classes might be the way to prevent the abuses to some of it more moderate opponents (reasonably) fear.
and it would allow user defined vector math type that will be useful in
tight loops. And you know we need them... :]
I'd like to think I'm going to do something pretty in 3D in a reasonable frame rate. And I like my math to look like math. :-) Dan
Sep 04 2001
parent "Rui Ferreira" <t5rui hotmail.com> writes:
I was just going on Bjarne's description.  To reuse them you make them a
member. Well, to use them I would make them a member, yes, but to REuse them I need to extend them in some way. In c++ that means inheritance to extend classes without the need for forwarding functions. Of course that, the very nature of concrete types makes them simple enough to avoid any substantial advantages from this, but since c++ allows it, natural uses have been found. I agree D should probably be simpler.
I do believe that we ought to prohibit virtual methods and polymorphism,
but I guess I don't have a good reason for that. We're not prohibiting anything... we're just extending C Structs to support a public interface.
I guess I will probably grow to like it since I would have to create an
entire class just to get the same results. Templates as smart pointers can be effective here. In fact smart pointers are so effective in c++ that they may now seem awkward to not be better integrated into the language itself. Provided it is available with a flexible extension mechanism of course. To push a single form of reference counted pointer or anything like that would be worst than the native template solution.
There is a strong element against overloading on this group though.  I
don't want to presume that there >>will be overloading. But limiting them to concrete classes might be the way to prevent the abuses to >>some of it more moderate opponents (reasonably) fear. True, but abuse would be not to support them. :] -Rui
Sep 05 2001
prev sibling parent reply "Rui Ferreira" <t5rui hotmail.com> writes:
 No. Structs are simply C'ish aggregations.
And why should they be in D ? Public data aggregation is against the very principle of information hiding. You provide those wonderful property fields and yet you preclude them for use in your basic data structure. C structs are your primary means of a program assembly, a composite type that acquires a new meaning once it is defined, it is a piece of my logical program, one that maps directly to the hardware. Your fundamental data structure is the memory block not the class. Concrete types take this a step further by using data hiding to ensure a consistent view of whatever concept we're supposed to be modeling. A unit of knowledge if you will. I do not see any benefit to introduce vtables and polymorphism into a otherwise, by definition; simple and to the point data structure.
 What's a "concrete" class?
Dan below gave some good examples.
 The vtable overhead is slight, and I think a reasonable tradeoff.
That doesn't sound 0-overhead to me. I consistently use concrete types, both for storage and as local variables to allow local computation of temporaries, mostly as arguments to a function. These are more common that you think. Once you acknowledge how your building blocks of data work you will use them to forward information to a function directly instead of separating the components to pass them to a function. That's old school C - a jumble of arguments of diverse nature. Not OOP - 2,3 arguments of concrete types. The way you handle your local variables should be clear and with well defined semantics. Basic types are not just your stock integer and floating point numbers. That is just the foundation layer, nothing else. Judging by your statement than you might as well retrofit 'int' with a vtable! The point is -- concrete types are exactly like them, whatever you call them, they are data types.
 D gets rid of "const" as part of the typing system, although you can
still declare constants. Amen to that.
 Structs are by value, and classes are by reference. 'out' and 'inout'
parameters are always passed by reference. Why structs by value only, does this mean that, if I have a large enough block of information it will not be accessed by indirection ? D wants to restrict the usage of pointers. That doesn't mean to lose them on your implementation. I want to access memory not copy it. -Rui Ferreira
Sep 04 2001
parent "Walter" <walter digitalmars.com> writes:
Rui Ferreira wrote in message <9n2esq$30mu$1 digitaldaemon.com>...
I do not see any benefit to introduce vtables and polymorphism into a
otherwise, by definition; simple and to the point data structure.
I think there may be misunderstanding here. Structs and classes are very different types. Structs do not have vtables and are not polymorphic. Classes have vtables and are polymorphic.
Sep 04 2001