• Advertisement
Sign in to follow this  

How would the optimal pointer syntax look like?

This topic is 2772 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been lightly looking into programming language design and when looking at the subject of pointers and manual memory management I became curious about something. Namely, if you had free reign, and were tasked with designing the syntax used for pointer operations ((de)allocation, (de)referencing, arithmetic and so on), what syntax would you settle on and why? Feel free to make up your own syntax if you feel that whatever is currently out there is lacking.

When replying, please supply examples of your syntax as well as the good points and bad points from your perspective regarding it.

EDIT:
Quote:
Original post by rip-off
I agree entirely. I am curious about what nem123's language design goals are. Without knowing that it is hard to make any real comments on the apparent choice to include pointers in it.


Yes, maybe I should have made this clear to begin with.

In reality, it's more me building a compiler (src->asm), the language design interest part is something that has been growing slowly while thinking about how stuff could be implemented and supported by the compiler (makes sense?).

In essence, with my compiler, and language, I'm aiming for a systems programming language with a somewhat better/nicer (subjective?) syntax then C. With support for OOP as far as what can be resolved at compile time. I intend to shy away from constructs that require additional run-time support (meaning, I'd like to be able to generate the least amount of CPU operations from a given set of code, this might be more of a compiler optimization issue though, rather then a language issue). Other then this, I don't have much of a plan for the language, features will be added ad-hoc if I deem them necessary/useful in the domain of system programming, or can be talked into implementing by other more experiences people.

[Edited by - nem123 on July 18, 2010 4:10:38 AM]

Share this post


Link to post
Share on other sites
Advertisement
When I started learning C I was confused with the way pointers were defined:
Type *pointer; // we define a pointer variable
Type value;

value = *pointer; // we dereference the pointer (* means going from pointer to value)
pointer = &value; // we take the address (& means going from value to pointer)

You see, when we define a pointer variable, we use the star *. However, any time after the definition, the star * is used to go from pointer to value. In the definition it reads like "we have a type Type, which we dereference, we go from pointer (Type) to value (*Type)". But this is not true. A more suiting symbol for pointer definition would be the ampersand &: "we have type Type, which we take the address from, we go from value (Type) to pointer (&Type)".
Type &pointer; // we define a pointer variable
Type value;

value = *pointer; // we dereference the pointer (* means going from pointer to value)
pointer = &value; // we take the address (& means going from value to pointer)

In C++ this clashes with references, but to me this would be a much better suiting syntax. It is more consistent, this way the * has not 3 (pointer definition, dereferencing, multiplying) but only 2 meanings. The & still keeps the same meaning across the code (binary / boolean operation, take address).

This is my point of view, I can remember this caused me trouble to understand pointers back then, if someone has an explanation for the use of * for pointer definition, I'd be glad to hear.

Share this post


Link to post
Share on other sites
Maybe something similar to ->, but perhaps the other way, e.g.:

int Value = <-PointerToValue;

Dunno though, I haven't really thought too much about it :)

Share this post


Link to post
Share on other sites
One thing that could be done would be to separate the concept of NULLness from reference semantics.

For example (based on C for clarity for the moment):

int? x = null; // optional integer, must be initialised

// Must use this:
if(int y = ?x) {
// "y" is the not-null value of x
}
// optional "else" clause for null values.



Another example:

int? foo() { /* ... */ }

while(int x = foo()) {
// use x
}
// Here when x becomes null.


Note that the de-referencing has no explicit operator, it is done as part of the conditional expression.

A reference (again, C syntax not necessarily representative):

int& x = 5; // Must be initialised
int ?y = foo();
int &z = y; // Illegal (y may be null)

std::vector<int> ?vec = /* ... */;
if(std::vector<int> &ref = vec) {
// ...
}



Here we can introduce some syntactic sugar:

int ?foo = /* ... */
if(foo) {
// foo is now in scope as a reference to int
std::cout << foo << '\n';
}


So that we have a shorthand for the common operation "if X != null, use X". It is equiv

Here optional variables are references, so there is no syntax for an optional reference. This means (for example) that you cannot return an optional temporary. This is more a function of me making most of this up right now rather than any gut belief that this should be the way.

I'm not sure about pointer arithmetic. It is pretty low level. But since you are talking about designing a language with pointers in it, then I suppose that is what you are aiming at.

Again I would be inclined to separate the concepts, because this is totally different from the above. Again, inspired by C:

int [] allocate(int n);

int [] array = allocate(42);
for(int [] pointer = array ; pointer != array + 42 ; ++pointer) {
int value = pointer[]; // inspired by pointer[0]
}


You could also go a more C++ version and have opt<int> ref<int> array<int> as the types, which would make them easier to think about in combination:

opt<array<int>>
opt<ref<int>>
ref<array<opt<int>>> // you may want to support typedefs...


Alternatively, "ref" "array" and "opt" could become keywords (in the above, they might only be keywords when used with <>):

opt array int
opt ref int
ref array opt int



I'm not sure if this was what you are looking for. I actually don't care about syntax itself all that much, its more about how expressive the langauge is. Plus as I said I made up a lot of this on the spot so maybe it doesn't make much sense.

In C, "void foo(int *x)" isn't as expressive as it could be. It doesn't tell you if the function expects NULL. It doesn't say if the function expects and array. It doesn't say if the function will write to the variable. Yes, there are hints we can give by using int [] x or const, but this is insufficient I think. The language should allow us to specify these semantic differences without resorting to comments.

Also, please include some form of inferred typing!

Share this post


Link to post
Share on other sites
Do you *really* need pointers? What do they buy you that e.g. references don't?

Personally, I'd like a slightly expanded C# syntax for references:

void foo<T>(T a)
void foo<T>(ref T a)
void foo<T>(out T a)
void foo<T>(const ref T a)

I'd also like nullable parameters to be explicitly marked (rather than vice versa). In other words, make null values the exception rather than the rule:

void foo<T>(T? a)
// or
void foo<T>(T a) where T : nullable


For actual pointers, I'd avoid the array-pointer duality of C/C++ (it really makes no sense and introduces a host of other problems). I quite like the C# approch here, which allows the use of pointers only in explicitly defined "unsafe" regions. Outside of C interop you really don't miss them at all.

Dereference of pointers/references can be handled with the dot operator (.) - there's no real reason for -> that I'm aware of. The compiler should be able to figure out and dereference automatically.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
Outside of C interop you really don't miss them at all.


Actually, you do. My code is full of pointers, though often hidden (in a custom smart pointer). I need to have pointers, else I cannot have heterogeneous arrays. I even have double pointers, that saves me a lot of if / else statements. For example, a checkbox has many states, you wouldn't want switch / if / else series to draw the correct state (which is a pointer to texture data), a simple (double) pointer is most elegant.

But it also depends on the language, in PHP there's no pointers. The language is pretty limited in what you can do (you can only output text for web stuff, which it is used most for). Most PHP programmers program pretty sloppy, delivering suboptimal code. I do too, simply because PHP doesn't let me use efficient, straightforward ways. Optimal code is also often irrelevant with PHP.

How do you want to keep track of large memory files without pointers? I don't find references suiting for that...

Share this post


Link to post
Share on other sites
Extend -> to cover "multiple layers" eg:

std::vector<Foo*> foos;
for(std::vector<Foo*>::iterator i=foos.begin();i!=foos.end(); ++i)
i-->bar();//not valid C++, you must do "(**i).bar()" or similar.







It would be useful if string literals and arrays had a way to exploit the fact that their length is known, eg:

//should this really need to use an strlen type method at runtime?
//The length was known when this was compiled after all...The length was known when this was compiled after all...
std::string a = "Hello World";




Maybe some kind of light weight array/string class that keeps the length in a constant which could be filled out at compile time.

string::string(FixedString str)
{
assign(str, str.size);
}




In the advent that the literal is immediately converted to a pointer (eg there was no overload, or it was just a "cosnt char *str = "Hello World" assignment) the compiler could obviously just do it the C++ way.



Quote:

Fiddler
Dereference of pointers/references can be handled with the dot operator (.) - there's no real reason for -> that I'm aware of. The compiler should be able to figure out and dereference automatically.

What about smart pointers, iterators, or any other object with an overloaded * and -> where the . isn't to helpful for most code?

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
Do you *really* need pointers? What do they buy you that e.g. references don't?


Pointer arithmetic? The syntax of adding 3 to a pointer doesn't really have a reference equivalent. And array-pointer duality makes perfect sense to me. The array is a pointer to an area of memory, and its elements are offsets from that pointer. It goes hand in hand with pointer arithmetic:
array[3]
// ... is essentially the same as ...
*(array + 3)
In the world of C, array notation is really just a convenient shorthand, though there can be times when using pointer arithmetic is actually a more straightforward way of expressing things (e.g. when you're reseating a pointer by an offset).

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
I need to have pointers, else I cannot have heterogeneous arrays.

Incorrect. You are thinking purely in terms of C or C++. In general, the above are achieved with some form of referential semantics, to which there are different solutions. True, these solutions typically involve things *like* pointers, but not the full combination of reference/optional/memory arithmetic that C++ pointers offer.
Quote:

I even have double pointers, that saves me a lot of if / else statements. For example, a checkbox has many states, you wouldn't want switch / if / else series to draw the correct state (which is a pointer to texture data), a simple (double) pointer is most elegant.

I'm not sure about that. It depends on exactly how you implemented your class. If your states are an array, you can use an array index to achieve the same effect, for instance. Plus, most checkboxes have two states, checked and unchecked. Besides, nearly every language can implement something like a pointer to a pointer.
Quote:

But it also depends on the language, in PHP there's no pointers. The language is pretty limited in what you can do (you can only output text for web stuff, which it is used most for). Most PHP programmers program pretty sloppy, delivering suboptimal code. I do too, simply because PHP doesn't let me use efficient, straightforward ways. Optimal code is also often irrelevant with PHP.

That seems pretty off topic. I think PHP is more powerful than you give it credit for, it can certainly do more than output text for web stuff. Even so, you haven't really linked the lack of pointers to any weaknesses PHP has.
Quote:
How do you want to keep track of large memory files without pointers? I don't find references suiting for that...

For higher level languages, this sort of implementation detail can be wrapped. For example, file offsets can be specified as large integers, and the wrapped native code can deal with turning this into a raw memory offset.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shinkage
Quote:
Original post by Fiddler
Do you *really* need pointers? What do they buy you that e.g. references don't?

Pointer arithmetic? The syntax of adding 3 to a pointer doesn't really have a reference equivalent. And array-pointer duality makes perfect sense to me. The array is a pointer to an area of memory, and its elements are offsets from that pointer. It goes hand in hand with pointer arithmetic:
array[3]
// ... is essentially the same as ...
*(array + 3)
In the world of C, array notation is really just a convenient shorthand, though there can be times when using pointer arithmetic is actually a more straightforward way of expressing things (e.g. when you're reseating a pointer by an offset).

Unimpressive. The most common use for pointer arithmetic is in extremely low level operations such as copying a block of arbitrary memory as a set of bytes. Most real code will use dynamic containers rather than arrays or pointers for storing data sets.

Having arrays and references generally nets the language 97% (or more) of the uses for pointers. And most of the other uses are unsafe anyway, and modern languages tend to shy away from giving them to programmers as there are workarounds (though they may not be as performant, e.g. member-wise serialisation rather than mulk memcpy/fwrite calls).

It is debatable whether these are strictly necessary. Such things are often overused for the rather dubious performance benefits - people worrying about taxing the CPU when their program is in reality waiting for the network or hard drive.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Unimpressive. The most common use for pointer arithmetic is in extremely low level operations such as copying a block of arbitrary memory as a set of bytes. Most real code will use dynamic containers rather than arrays or pointers for storing data sets.

Having arrays and references generally nets the language 97% (or more) of the uses for pointers. And most of the other uses are unsafe anyway, and modern languages tend to shy away from giving them to programmers as there are workarounds (though they may not be as performant, e.g. member-wise serialisation rather than mulk memcpy/fwrite calls).

It is debatable whether these are strictly necessary. Such things are often overused for the rather dubious performance benefits - people worrying about taxing the CPU when their program is in reality waiting for the network or hard drive.


Keeping in mind of course that one of the stated core design goals of C and C++ is being a systems programming language, where such things are overwhelmingly important? Whether YOU use it somewhat beside the point, because I assure you, if you're programming a hardware driver or an operating system it can be VERY important, and as such it would be a somewhat silly notion that the languages used to perform those tasks should do without it.

This brings up an interesting point, and I think only serves to illustrate the fact that there is no "best" language, or even best design for a particular feature. If a language is being used for systems programming going to make very different design choices than one that's aimed at high level application programming, and that's only sensible.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shinkage
Keeping in mind of course that one of the stated core design goals of C and C++ is being a systems programming language, where such things are overwhelmingly important? Whether YOU use it somewhat beside the point, because I assure you, if you're programming a hardware driver or an operating system it can be VERY important, and as such it would be a somewhat silly notion that the languages used to perform those tasks should do without it.

This brings up an interesting point, and I think only serves to illustrate the fact that there is no "best" language, or even best design for a particular feature. If a language is being used for systems programming going to make very different design choices than one that's aimed at high level application programming, and that's only sensible.

I agree entirely. I am curious about what nem123's language design goals are. Without knowing that it is hard to make any real comments on the apparent choice to include pointers in it.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
I agree entirely. I am curious about what nem123's language design goals are. Without knowing that it is hard to make any real comments on the apparent choice to include pointers in it.


Well, assuming the language is for game development among other things, and particularly if it's intended to be portable to embedded systems/consoles, I think including pointers is a sensible (even necessary) idea. Desktop-only game development not so much.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
I'm not sure about that. It depends on exactly how you implemented your class. If your states are an array, you can use an array index to achieve the same effect, for instance. Plus, most checkboxes have two states, checked and unchecked. Besides, nearly every language can implement something like a pointer to a pointer.


For example, my checkbox has 3 states (checked, unchecked, mixed). For each state I have a pointer to the resource / texture. I could keep track using an Enum as to what state it resides in, this would require if / else checking, which can become a mess the more states you have. The way I implemented it, is having a pointer to the pointer to the resource / texture. That way, whenever a state changes I can change the double pointer, and at draw time just dereference. It is also easy with RAII to make sure the pointer always points to valid data.

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
Quote:
Original post by rip-off
I'm not sure about that. It depends on exactly how you implemented your class. If your states are an array, you can use an array index to achieve the same effect, for instance. Plus, most checkboxes have two states, checked and unchecked. Besides, nearly every language can implement something like a pointer to a pointer.


For example, my checkbox has 3 states (checked, unchecked, mixed). For each state I have a pointer to the resource / texture. I could keep track using an Enum as to what state it resides in, this would require if / else checking, which can become a mess the more states you have. The way I implemented it, is having a pointer to the pointer to the resource / texture. That way, whenever a state changes I can change the double pointer, and at draw time just dereference. It is also easy with RAII to make sure the pointer always points to valid data.


This is trivial to implement even in languages that don't support pointers at all. E.g. F#:

type Texture (id : int) =
let Id = id // An OpenGL texture id

type CheckBoxState (icon : Texture) =
let Icon = icon
static let _enabled = new CheckBoxState (new Texture(1))
static let _disabled = new CheckBoxState (new Texture(2))
static let _mixed = new CheckBoxState (new Texture(3))
static member Enabled = _enabled
static member Disabled = _disabled
static member Mixed = _mixed

type CheckBox (?state : CheckBoxState) =
let mutable _state = defaultArg state CheckBoxState.Disabled
member this.State
with public get () = _state
and public set (state) = _state <- state

let main () =
let a = new CheckBox () // Defaults to Disabled
let b = new CheckBox (CheckBoxState.Enabled)
a.State <- CheckBoxState.Mixed

main ()


Share this post


Link to post
Share on other sites
I couldn't do some of what I do without pointer arithmetic. Well, I could, but it would include an extra dereference which would negate the reason for using pointers in the first place.

I maintain several large blocks of memory for entity data, and use offsets to access the individual fields. Each data element can be a different type, and so the type sizes are different. Can't use array offsets for that.

This is done so that the data is all in one place for 4 reasons.

1) dramatic increase in overall processing speed.
2) I can share any data instance between the engine and script.
3) Certain data instances serve as data buffers for VBO/IBO operations.
4) The structure simplifies object instancing from script.

(I use pascal mostly, with some C++)

I never write property containers like this:


Obj.MyPropertyHelper.Add('Health',100);
health = Obj.MyPropertyHelper.Get('Health');




I first define classes/fields in script, and use that to set up the custom data instances. Then, to access a given field from script I simply perform pointer arithmetic behind the scenes, adding the field offset to the data instance address.

The script looks nice and clean:


player.health -= monster.damage
if (player.health <= 0)
player @@ Die
monster @@ Cheer
end




and behind the scenes, the system performs the pointer arithmetic to surface the appropriate value:


result := psingle(pInstance "plus" var.Offset)^
// I used "plus" because the plus sign wouldn't show in preview




Also at the lower system level, in plugins or whatnot, I can sometimes map predefined structures atop a given object's instance and access the fields directly from a record (struct in c).


TObjectMap = record
Health: integer;
end;
PObjectMap = ^TObjectMath; // pointer declaration in pascal

procedure DisplayHealth(obj: TmObject);
var
data: PObjectMap;
begin
data = Obj.Instance;
ShowMessage('health = ' "plus" inttostr(data.Health));
end;




Instance data can also be traversed if necessary using the same concept:


// simplified - no error checking or whatever
pInstance = Obj.Instance;
pNextInstance = pInstance "plus" Obj.InstanceSize;




Best of both worlds, imo. And, all courtesy of pointer arithmetic.

-----------------

Also, notice in the above example how pascal uses dot notation with pointers. no need for the ->. I like that, too.

The one other thing I would change with pointers would be to allow only 1 pointer type to be declared for any type. And, that the pointer would have to be declared at the same place where the structure is defined.

Node* root (would be illegal)

but you could declare root with the predefined pointer to Node.

pNode root (would be allowed, assuming pNode was previously defined)

Share this post


Link to post
Share on other sites
I like the c/c++ way, except for how to create pointers.. creating 2 pointers in one line is ugly for example:
int *foo, *bar;
imho the type should be seperate from the name.
also the standard gives too much freedom on how to do it:
int *foo;
int* bar;
int * foobar;

I guess, I'd like the second one most, so you could do:
int* foo, bar;

also I like having both pointers and references. references being always safe (never NULL),
and pointers having the advantage of NULL (so you dont have to allocate memory when not needed)

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Make the dereferencing operator postfix instead of prefix.


Are you referring to how C/C++ does it?, like so:

C/C++: *a
Your suggestion: a*




Quote:
Original post by Decrius
You see, when we define a pointer variable, we use the star *. However, any time after the definition, the star * is used to go from pointer to value. In the definition it reads like "we have a type Type, which we dereference, we go from pointer (Type) to value (*Type)". But this is not true. A more suiting symbol for pointer definition would be the ampersand &: "we have type Type, which we take the address from, we go from value (Type) to pointer (&Type)".

A very good point here, how do you feel about the use of the ampersand and star symbols? For example, if you have lots of dereferencing and address-fetching in your code, does the code not become harder to read with lots of symbols with special meaning (this also applies to symbols like '&&', '||', '^' and so on)? I guess this is something you get use to with time, but still, how do you feel about this?



Quote:
Original post by f8k8
Maybe something similar to ->, but perhaps the other way, e.g.:

int Value = <-PointerToValue;

Dunno though, I haven't really thought too much about it :)

I thing the Go programming language does something like this, or that might just have been for their 'GoRoutines' or whatever they are calling those 'concurrency enabled functions' they have in there (not too involved with that language).
I'm not sure I like this syntax myself though, does it make things more clear? Possibly. Is it better then a straight up star for dereferencing? doubtfull.



Quote:
Original post by rip-off
I'm not sure about pointer arithmetic. It is pretty low level. But since you are talking about designing a language with pointers in it, then I suppose that is what you are aiming at.

In reality, it's more me building a compiler (src->asm), the language design interest part is something that has been growing slowly while thinking about how stuff could be implemented and supported by the compiler (makes sense?).

Thank you for the suggestions on alternative syntax here. I like the one about using keywords to describe types. This is what Java does to some degree if I'm not mistaken. A side-effect being the increase in verbosity, perhaps too much verbosity?

Quote:
Original post by rip-off
In C, "void foo(int *x)" isn't as expressive as it could be. It doesn't tell you if the function expects NULL. It doesn't say if the function expects and array. It doesn't say if the function will write to the variable. Yes, there are hints we can give by using int [] x or const, but this is insufficient I think. The language should allow us to specify these semantic differences without resorting to comments.


About NULL, perhaps there is someway to avoid its use/existence all-together, by requiring that all references/pointers be initialized (how do you deal with function returns? By not allowing return 0? What effects would this have?).
I agree in regards to you being required to specify semantic differences.

Quote:
Original post by rip-off
Also, please include some form of inferred typing!

I've been thinking about inferred typing, I'm not sure I like the concept though. The compiler I'm building is targeting a statically typed language, and introducing inferred typing could be confusing for the programmer, not knowing what type a particular symbol has. And how would you deal with functions that has return statement for multiple types? Throw an error I guess :). I might be wrong in this regard though, I don't have much experience with type inference too be honest.



Quote:
Original post by Fiddler
Do you *really* need pointers? What do they buy you that e.g. references don't?

If we take C++ for example, with a reference object, you cannot refer directly to the reference object, only to the object that it references to. And we also have the issue of not being able to 'reseat' a reference, something that can be done with pointers. If this last point is a good or bad one can be discussed.

Quote:
Original post by Fiddler
I'd also like nullable parameters to be explicitly marked (rather than vice versa). In other words, make null values the exception rather than the rule:
void foo<T>(T? a)
// or
void foo<T>(T a) where T : nullable

Interesting! This is the next-best thing to banning NULL with the use of pointers/references, I wonder if this could be resolved at compile-time or if you need some run-time components to insure correctness.

Quote:
Original post by Fiddler
Dereference of pointers/references can be handled with the dot operator (.) - there's no real reason for -> that I'm aware of. The compiler should be able to figure out and dereference automatically.

Indeed.



Quote:
Original post by rip-off
Quote:
Original post by Decrius
I need to have pointers, else I cannot have heterogeneous arrays.


Incorrect. You are thinking purely in terms of C or C++. In general, the above are achieved with some form of referential semantics, to which there are different solutions. True, these solutions typically involve things *like* pointers, but not the full combination of reference/optional/memory arithmetic that C++ pointers offer.

Do you have some example/resource describing different solutions of referential semantics?

Original post by rip-off
Quote:

How do you want to keep track of large memory files without pointers? I don't find references suiting for that...

For higher level languages, this sort of implementation detail can be wrapped. For example, file offsets can be specified as large integers, and the wrapped native code can deal with turning this into a raw memory offset.
Interesting alternative, do you thing that this could also be implemented in a 'lower-level language'?

Quote:
Original post by rip-off
I agree entirely. I am curious about what nem123's language design goals are. Without knowing that it is hard to make any real comments on the apparent choice to include pointers in it.

Yes, maybe I should have made this clear to begin with, I'll update my original post as well as try to describe it in more detail here.

In essence, with my compiler, and language, I'm aiming for a systems programming language with a somewhat better/nicer (subjective?) syntax then C. With support for OOP as far as what can be resolved at compile time. I intend to shy away from constructs that require additional run-time support (meaning, I'd like to be able to generate the least amount of CPU operations from a given set of code, this might be more of a compiler optimization issue though, rather then a language issue). Other then this, I don't have much of a plan for the language, features will be added ad-hoc if I deem them necessary/useful in the domain of system programming, or can be talked into implementing by other more experiences people.



Quote:
Original post by Whatz
The one other thing I would change with pointers would be to allow only 1 pointer type to be declared for any type. And, that the pointer would have to be declared at the same place where the structure is defined.


Node* root (would be illegal)

but you could declare root with the predefined pointer to Node.

pNode root (would be allowed, assuming pNode was previously defined)

I like this, having a specific type for pointers, not just tacking on a star or other symbol to indicate that we want to declare a pointer.

Share this post


Link to post
Share on other sites
Maybe I'm naive at what goes on under the surface, but - by far! - the most important change to C++ for me would be a generic function pointer for any given function arguments. Function pointers are so useful; oftentimes, they are used for time-critical code, and to implement a functor class seems a very roundabout and clunky way to fix the issue. The alternative would seem to be passing dummy arguments to functions so they all look alike, or using switch/conditions to call a particular function. But maybe someone can clue me in to a better way to implement this pattern.. I've been wanting to ask, and, well, here's this thread..

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
This is trivial to implement even in languages that don't support pointers at all. E.g. F#:
*** Source Snippet Removed ***


Forgive my very limited F# knowledge, but where is the draw function without any if / else clutter?

Quote:
Original post by nem123
A very good point here, how do you feel about the use of the ampersand and star symbols? For example, if you have lots of dereferencing and address-fetching in your code, does the code not become harder to read with lots of symbols with special meaning (this also applies to symbols like '&&', '||', '^' and so on)? I guess this is something you get use to with time, but still, how do you feel about this?


Yes, it becomes harder to read code from chaotic programmers. I have seen some sloppy C code, C allows for much sloppy code, but that doesn't mean people have to. Many C programmers have their own code style and adhere to it, this bit of discipline is needed with all languages, but especially for C.

The alternative would be adding a keyword or implementing it in the standard library (and from your goal I don't suspect you will develop that?). A keyword would make lengthier code. I would strive to keep pointer syntax pretty short (* and &) as they're one of the most used commands in ASM, and translate very well to ASM, giving you actually make an ASM wrapper like C. The use of * and & in combination with && || etc. has never given me trouble or sloppy code.


The difference between pointers and references is this:
- slightly different syntax in definition and usage
- no NULL
- no reseating
- with const you can pass in-place constructed objects

Adding NULL support for reference could be nice, but also brings both concepts even closer to each other (then what is technically the difference?), you could as well merge them...

I also don't see why reseating is not allowed, is this technically not possible (I believe it is)?
const Type &reference = Type(1);
&reference = Type(2); // Type(1) destructed

Share this post


Link to post
Share on other sites
After browsing through all the posts I did't find anyone who mentioned what pointer arithmetic really IS:

If you add '3' to a pointer, the (C) compiler will in reality add 3 * sizeof(type). This is why you have the "type *var" constructs - the copiler needs to know the type the pointer is pointing at. In essence the pointer is the C iterator type.

So if what you want your language to do is low level memory management - do you really *need* pointer arithmetic? It may be just me, but most of the time I do something with memory I either use void* or unsigned char* anyways.

Spend some time to analyse what basic abstractions are implemented by the C pointer.
-> Pass by reference
-> Iteration
-> Retrieve object reference
-> any more?

C implements all of these as close to the system as possible, so they all work directly on memory addresses. Also, C makes this transparent for the programmer. That's not how it has to be for every language.


You should check if your high level language needs (iteration, references to (non OO) 'objects') can be implemented differently from C, and if it isn't enough to have a special ADDRESS type, and an operation converting a reference to an ADDRESS.
Do the rest using another abstraction, and don't guarantee the underlying addresses like C does. Or don't support them at all if you don't feel like it.

If you then use the language to implement whatever you want to implement with it, you can easily find the additional abstractions you want it to support. Don't re-invent C.

By the way I'm no fan of languages that hide it in the language spec when the compiler uses pass by reference and when it uses pass by value. Make it explicit the way C++ does :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
The alternative would be adding a keyword or implementing it in the standard library (and from your goal I don't suspect you will develop that?). A keyword would make lengthier code. I would strive to keep pointer syntax pretty short (* and &) as they're one of the most used commands in ASM, and translate very well to ASM, giving you actually make an ASM wrapper like C. The use of * and & in combination with && || etc. has never given me trouble or sloppy code.


No plans for a standard library at this moment, might come when the language/compiler is sufficiently mature.


===========================================================
Here is the syntax that I've come up with myself, I'm a bit hesitant about it and that's why I started this thread.


Declaration:
int.addr a
int.addr[] b ; Pointer to pointers.

Accessing memory address we point to:
a.addr
b[5].addr

Pointer arithmetic:
a.addr++
a.addr + 3
b[5].addr++
b[5].addr + 3

Dereferencing (notice how I think the compiler should do this by default):
printf("%d", a);
printf("%d", b[5]);


I find that this could possibly be a bit more clear then straight up using star and ampersand like C does it. I have a feeling that there are some cases where the syntax could become a bit clunky/vague here.

Any thoughts here?

Share this post


Link to post
Share on other sites
Quote:
Original post by nem123
Here is the syntax that I've come up with myself, I'm a bit hesitant about it and that's why I started this thread.


Declaration:
int.addr a
int.addr[] b ; Pointer to pointers.

Accessing memory address we point to:
a.addr
b[5].addr

Pointer arithmetic:
a.addr++
a.addr + 3
b[5].addr++
b[5].addr + 3

Dereferencing (notice how I think the compiler should do this by default):
printf("%d", a);
printf("%d", b[5]);


I find that this could possibly be a bit more clear then straight up using star and ampersand like C does it. I have a feeling that there are some cases where the syntax could become a bit clunky/vague here.

Any thoughts here?


How about treating every variable as a pointer? So you would write:

Declaration:
var a, b; no type, type is detected when the var is used

Accessing memory address we point to:
a.address = ...

Accessing value at that address:
a = 0;

Creating a pointer to pointer:
a = b.address;

Transforming into a reference:
a.address = b.address;

Resetting to default address that was allocated when declared:
a.address = RESET;

Display the value:
print("Value of a = " + a + ";eoln");


And btw, if you're making a new language try to lose the c/c++ style, or else you will only build a c/c++ clone = fail

Share this post


Link to post
Share on other sites
Take a look at D, which happens to fit your design goals pretty nicely. It might be a good source of inspiration.

Quote:
Original post by Decrius
Forgive my very limited F# knowledge, but where is the draw function without any if / else clutter?


The draw function might look something like this:

open OpenTK.Graphics.OpenGL

let draw (c : CheckBox) =
// OpenGL 1.1 for simplicity
GL.BindTexture TextureTarget.Texture2D c.State.Texture.Id
GL.Begin BeginMode.Quads
...
GL.End ()



There's no need for conditionals: c.State.Texture.Id provides the correct texture for each CheckBoxState. Adding new CheckBoxStates is also trivial.

Just wanted to show that this 'pointer-to-pointer' approach can be implemented in pretty much any programming language, without using pointers (this code would look almost identical in Java, Python, C# or even C++ w/ references).

Back on topic:
Quote:
Original post by nem123

int.addr[] b ; Pointer to pointers.



Why not:

int.addr.addr b ; Pointer to pointer

Square brackets [] tend to mean 'array' in many programming languages and changing that meaning could be confusing.

How would you get the address of a variable?

int.addr pa = a.addr

Slightly verbose but not all that bad.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement