Because you tell it to:
int a[10]; // Normal C array
Vector v = newVector(10,sizeof(int));
a[2] = 5;
v[2] = 5;
> <snip>
>> ... Operator overloading provides a simple and elegant solution as
>> I have been claiming since several years now.
>
> I think treating initialisation as assignment and, if I recall
> correctly, *not* treating argument passing as assignment makes your
> operator overloading much less useful than it might have been.
>
All argument passing are assignments in standard C.
But if you want C++, no, it is not C++.
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
> Ben Bacarisse wrote:
>> jacob navia <ja...@nospam.com> writes:
>>
>>> Keith Thompson wrote:
>>> [snip]
>>>
>>>> What could be done, I suppose, is to add an entirely new array-like
>>>> construct to C, one that doesn't depend on pointer semantics for its
>>>> fundamental operations or decay to a pointer in most contexts. Let's
>>>> call it a "vector".
>>> Correct. This is the way that lcc-win has choosen. Using
>>> operator overloading of the '[' and ']' operators lcc-win
>>> offers a true array type that doesn't "decay" to anything.
>>
>> Way off-topic now so I've set followup-to comp.compilers.lcc, but I
>> can't see how that can do anything. In this code:
>>
>> int a[10];
>> f(a);
>>
>> there are no [] operators, so how does the compiler know which sort of
>> array I want?
>>
>
> Because you tell it to:
>
> int a[10]; // Normal C array
> Vector v = newVector(10,sizeof(int));
>
> a[2] = 5;
> v[2] = 5;
I added #include <vector.h> and wrapped it in a main function, but
this does not compile. Are vectors a work in progress?
At any rate, as far as I can see you agree with me. You don't do it
as you seemed to be suggesting with an array that does not decay to a
pointer. You just use a new type -- most likely some sort of struct
type.
>> <snip>
>>> ... Operator overloading provides a simple and elegant solution as
>>> I have been claiming since several years now.
>>
>> I think treating initialisation as assignment and, if I recall
>> correctly, *not* treating argument passing as assignment makes your
>> operator overloading much less useful than it might have been.
>>
>
> All argument passing are assignments in standard C.
Yes I know. I was curious as to why they seem to be excluded, since
they are, in effect assignments. In other words, having defined
assignment for type T from type X, I'd expect to see it used when
passing an X to function taking a T.
However, I now discover that for some reason one can't define
assignment between two type T objects. That seems to exclude lots of
useful implementations like reference counting and copy on write. Are
the precise semantics of operator overloading and with is and is not
permitted written down anywhere?
> But if you want C++, no, it is not C++.
Eh? I'd like it to be consistent. Are you saying that the only way
to do overloading in C properly is to move all the way to C++?
--
Ben.
#include <math.h>
#include <time.h>
#include <vector.h>
int printInt(void *pint)
{
return printf(" %d",*(int *)pint);
}
void print_vector(vector *v)
{
iterate_vector(v,printInt);
printf("\n");
}
int printDouble(void *pdouble)
{
return printf(" %g",*(double *)pdouble);
}
int comparInts(const void *p1,const void *p2)
{
return (*(int *)p1) - (*(int *)p2);
}
void *addInts(void *pi1,void *pi2,void *presult)
{
*(int *)presult = (*(int *)pi1) + (*(int *)pi2);
return presult;
}
void *intSqrt(void *pint,void *presult)
{
int *pi = (int *)pint;
double *pd = (double *)presult;
*pd = sqrt((double)*pi);
return presult;
}
void *accumInts(void *pi1,void *presult)
{
int s;
s = *(int *)pi1;
s += *(int *)presult;
*((int *)presult) = s;
return presult;
}
int main(void)
{
vector *v,*s,*a,*ac,*dv;
int i,siz;
v = new_default_vector(20,sizeof(int));
siz = get_size_vector(v);
for (i=0; i<siz;i++) {
set_element_vector(v,i,&i);
}
printf("Initial vector:\n");
print_vector(v);
i = 5987;
v = insert_vector(v,3,&i);
printf("after insertion position 3\n");
print_vector(v);
i = -5987;
v = insert_vector(v,3,&i);
printf("after insertion position 3\n");
print_vector(v);
sort_vector(v,comparInts);
printf("after sorting\n");
print_vector(v);
s = subrange_vector(v,1,6);
printf("sub range 1,6\n");
print_vector(s);
a = binary_map_vector(v,s,addInts);
printf("addition of subrange with sorted vector\n");
print_vector(a);
i = 0;
ac = scan_vector(v,accumInts,&i);
printf("Sum of v is %d\n",i);
i = 1654;
set_element_vector(v,0,&i);
dv = new_default_vector(10,sizeof(double));
cast_vector(dv,v,intSqrt);
iterate_vector(dv,printDouble);
return 0;
}
> At any rate, as far as I can see you agree with me. You don't do it
> as you seemed to be suggesting with an array that does not decay to a
> pointer. You just use a new type -- most likely some sort of struct
> type.
>
Operator overloading works with new types. This avoid all the problems
of mixing two data structures that are completely different with the
same notation.
>>> <snip>
>>>> ... Operator overloading provides a simple and elegant solution as
>>>> I have been claiming since several years now.
>>> I think treating initialisation as assignment and, if I recall
>>> correctly, *not* treating argument passing as assignment makes your
>>> operator overloading much less useful than it might have been.
>>>
>> All argument passing are assignments in standard C.
>
> Yes I know. I was curious as to why they seem to be excluded, since
> they are, in effect assignments. In other words, having defined
> assignment for type T from type X, I'd expect to see it used when
> passing an X to function taking a T.
>
They are not excluded. I may have bugs in my implementation.
> However, I now discover that for some reason one can't define
> assignment between two type T objects.
You mean
T a,b;
a=b;
??
The problem is that this is ALREADY defined in the standard
language, and I tried to stay within C.
> That seems to exclude lots of
> useful implementations like reference counting and copy on write. Are
> the precise semantics of operator overloading and with is and is not
> permitted written down anywhere?
>
Yes, in a document that I have posted several times in comp.std.c.
Nobody answered.
>> But if you want C++, no, it is not C++.
>
> Eh? I'd like it to be consistent. Are you saying that the only way
> to do overloading in C properly is to move all the way to C++?
>
Surely not. I just wanted to be clear.
> Ben Bacarisse wrote:
>> I added #include <vector.h> and wrapped it in a main function, but
>> this does not compile. Are vectors a work in progress?
>>
<snip vector example>
Right. I read the tutorial. What puzzled me is why you would post
incorrect syntax when explaining something about your own system.
>> At any rate, as far as I can see you agree with me. You don't do it
>> as you seemed to be suggesting with an array that does not decay to a
>> pointer. You just use a new type -- most likely some sort of struct
>> type.
>
> Operator overloading works with new types. This avoid all the problems
> of mixing two data structures that are completely different with the
> same notation.
Then I think you should have replied to Keith by saying that you do
it a different way. He was suggesting something else.
>>>> <snip>
>>>>> ... Operator overloading provides a simple and elegant solution as
>>>>> I have been claiming since several years now.
>>>> I think treating initialisation as assignment and, if I recall
>>>> correctly, *not* treating argument passing as assignment makes your
>>>> operator overloading much less useful than it might have been.
>>>>
>>> All argument passing are assignments in standard C.
>>
>> Yes I know. I was curious as to why they seem to be excluded, since
>> they are, in effect assignments. In other words, having defined
>> assignment for type T from type X, I'd expect to see it used when
>> passing an X to function taking a T.
>>
>
> They are not excluded. I may have bugs in my implementation.
It is not important to me. I was just curious about why it did not
work.
>> However, I now discover that for some reason one can't define
>> assignment between two type T objects.
>
> You mean
> T a,b;
>
> a=b;
>
> ??
Yes.
> The problem is that this is ALREADY defined in the standard
> language, and I tried to stay within C.
But you are extending C. How odd to have decided this useful facility
is not permitted.
>> That seems to exclude lots of
>> useful implementations like reference counting and copy on write. Are
>> the precise semantics of operator overloading and with is and is not
>> permitted written down anywhere?
>>
>
> Yes, in a document that I have posted several times in comp.std.c.
> Nobody answered.
I can't image you mean the same document that I read. That is in no
way a specification. It would be impossible to design a program based
on that information and equally impossible to tell if there is a bug
in the implementation. Maybe I missed the document you mean.
--
Ben.
What puzzled me is why you would post
incorrect syntax when explaining something about your own system.
Yes, I remembered incorrectly.
>
> I can't image you mean the same document that I read. That is in no
> way a specification. It would be impossible to design a program based
> on that information and equally impossible to tell if there is a bug
> in the implementation. Maybe I missed the document you mean.
>
http://www.q-software-solutions.de/~jacob/
There you will find a link to the specifications.
It would be very good for everybody if you would develop them
with me.
> Ben Bacarisse wrote:
>> Maybe I missed the document you mean.
>>
> http://www.q-software-solutions.de/~jacob/
> There you will find a link to the specifications.
Ah, yes. That says a little more but not really enough. For example
I don't see anything about not allowing
T &operator=(T&, T&);
lcc-win32 seems to reject
T &operator=(T&, T*);
but that is not explained. Is that a problem with the compiler or the
specification?
How many times is operator= called in these cases:
T &operator=(T& x, int i) { ... }
T a1[5] = {1,2};
T a2 = {3};
(T[2]){1,2};
struct S { T t; };
S s1 = {1};
S s2 = {.x = 2};
S as[5] = {1,2};
Is the following permitted:
const T x = 42;
x = 43;
The compiler allows it but the specifications says nothing about it.
What is the meaning of a pointer argument? What does the remark
"References can be replaced by arrays of length 1." mean?
After reading the specification, I have more questions than when I started.
> It would be very good for everybody if you would develop them
> with me.
We disagree to much. I've already said I think it is a mistake to
consider initialisation as the same as assignment, for example. I
think we just see thing far too differently.
--
Ben.
The prolem with that construct is that it has a well defined meaning in
C. The code
T a,b;
a=b;
means there is a bitwise copy from b to a. If we would allow the
overloading of the assignment operator, then the lecture of the code
would be more complicated as it is now.
One way out could be to allow:
a += b;
to have the meaning YOU want, and leave a=b; alone. Would that be
acceptable to you?
> lcc-win32 seems to reject
>
> T &operator=(T&, T*);
>
> but that is not explained. Is that a problem with the compiler or the
> specification?
>
Normally, references are read only. They can't be changed except
at initialization (or first assignment). Why would you like to allow
that? What would be the use of that code?
> How many times is operator= called in these cases:
>
> T &operator=(T& x, int i) { ... }
>
> T a1[5] = {1,2};
I see above only one assignment. But that assignment is not conforming
to the specification of the overloaded operator. We could issue a
"Too many initializers" error message, or call it twice and keep the
last result. It depends on seeing {1,2} as a single object or not.
In case of doubt, we could do as C++ does.
> T a2 = {3};
This is a conforming call of the assignment operator.
But this can be done only at compile time, if at global
level since we have no function calls before main().
> (T[2]){1,2};
>
If you mean
T tab[2] = {1,2};
then two calls should be done.
> struct S { T t; };
> S s1 = {1};
One.
> S s2 = {.x = 2};
Did you mistype? What is "x"? It is the T t member?
> S as[5] = {1,2};
>
Two calls to T's initializer.
> Is the following permitted:
>
> const T x = 42;
> x = 43;
>
> The compiler allows it but the specifications says nothing about it.
This is the old problem of "const" in C that is not really
const...
>
> What is the meaning of a pointer argument?
This means that there are operators that have a meaning in C
when using pointers.
Operator ADD/SUB is well defined in C for
Pointer + integer
Pointer - integer
Pointer - Pointer
That is why pointer operator overloading is restricted.
> What does the remark
> "References can be replaced by arrays of length 1." mean?
>
It means that if you write
void function(T s[]);
T s[1];
The structure is always passed by reference. A hack surely,
but a valid one.
> After reading the specification, I have more questions than when I started.
>
Normal.
>> It would be very good for everybody if you would develop them
>> with me.
>
> We disagree to much. I've already said I think it is a mistake to
> consider initialisation as the same as assignment, for example. I
> think we just see thing far too differently.
>
You can contribute by discussing your point of view.
Thanks for your interest in this.
> Ben Bacarisse wrote:
>> jacob navia <ja...@nospam.com> writes:
>>
>>> Ben Bacarisse wrote:
>>>> Maybe I missed the document you mean.
>>>>
>>> http://www.q-software-solutions.de/~jacob/
>>> There you will find a link to the specifications.
>>
>> Ah, yes. That says a little more but not really enough. For example
>> I don't see anything about not allowing
>>
>> T &operator=(T&, T&);
>>
>
> The prolem with that construct is that it has a well defined meaning in
> C. The code
> T a,b;
> a=b;
> means there is a bitwise copy from b to a. If we would allow the
> overloading of the assignment operator, then the lecture of the code
> would be more complicated as it is now.
>
> One way out could be to allow:
> a += b;
> to have the meaning YOU want, and leave a=b; alone. Would that be
> acceptable to you?
I am not asking because I want any particular semantics. You are
free to choose the meanings you think are right. My comment was that
the specification (or what you thought of as a specification) did not
say anything about this case (unless I missed it). It is not a
specification and will not be taken seriously unless all legal cases
are given meanings and all illegal cases are decumented.
>> lcc-win32 seems to reject
>>
>> T &operator=(T&, T*);
>>
>> but that is not explained. Is that a problem with the compiler or the
>> specification?
>>
>
> Normally, references are read only. They can't be changed except
> at initialization (or first assignment). Why would you like to allow
> that? What would be the use of that code?
I don't want anything form you, please. The specification does not
say if the above is allowed. It is not a specification unless it
does.
>> How many times is operator= called in these cases:
>>
>> T &operator=(T& x, int i) { ... }
>>
>> T a1[5] = {1,2};
>
> I see above only one assignment. But that assignment is not conforming
> to the specification of the overloaded operator. We could issue a
> "Too many initializers" error message, or call it twice and keep the
> last result. It depends on seeing {1,2} as a single object or not.
I think you don't understand your own compiler. Your specification
says that the overloaded = is called when arrays are initialised so I
wanted to know if it would be called twice of 5 times in the above case.
Your compiler calls it twice, but I expected 5. Neither is "right"
but you have not specified how overloading works with arrays unless I
can tell from reading the document.
> In case of doubt, we could do as C++ does.
>
>> T a2 = {3};
>
> This is a conforming call of the assignment operator.
The you have a bug in lcc-win32. operator= is called when I write:
T a2 = 3;
but not when I write:
T a2 = {3};
which I though was a deliberate (although potentially confusing)
feature to allow aggregate initialisation without using the overloaded
operator. However, the real point is that your specification is too
vague unless I can tell what lcc-win32 should do with both of these.
I should have been able to tell that there was bug without waiting for
you to tell me that there should have been a call to the assignment
operator.
> But this can be done only at compile time, if at global
> level since we have no function calls before main().
Yes, we've talked about this before and I disagree about your choice
on this.
>> (T[2]){1,2};
>>
>
> If you mean
> T tab[2] = {1,2};
>
> then two calls should be done.
Why two here? Did you not see the array in the example above?
Anyway, I did not mean what you wrote. Your specification has another
gap -- it does not say what happens when an aggregate is initialised
using a compound literal.
(T[2]){1,2};
is valid C and I'd expect you to make two calls to operator=. I'd
expect five if I write:
(T[5]){1,2};
but you spec says nothing about this form.
>> struct S { T t; };
>> S s1 = {1};
>
> One.
>
>> S s2 = {.x = 2};
>
> Did you mistype? What is "x"? It is the T t member?
Yes, should have been ".t = 2". I am sure you know lcc-win32 traps on
this syntax. Presumably it should simply call operator= once.
BTW, as an aside, I noticed that this program:
typedef struct T { int i; } T;
typedef struct S { T t; } S;
int main(void)
{
S s = {42};
return s.t.i;
}
is refused by lcc-win32 but I *think* is is valid, despite the missing
second {}s round the 42.
>> S as[5] = {1,2};
>
> Two calls to T's initializer.
OK. I'd have expected 5. The spec does not say what happens with
extra array elements. lcc-win32 reports two errors and refuses to
compile. (I am not complaining about that, I can see you are still
working on what overloading should and should not do in various
cases.)
>> Is the following permitted:
>>
>> const T x = 42;
>> x = 43;
>>
>> The compiler allows it but the specifications says nothing about it.
>
> This is the old problem of "const" in C that is not really
> const...
No. This is a new problem of an extension that does not warn the
programmer when they modify a read-only object. I C, a good compiler
tells me if I try to modify a const object.
>> What is the meaning of a pointer argument?
>
> This means that there are operators that have a meaning in C
> when using pointers.
>
> Operator ADD/SUB is well defined in C for
>
> Pointer + integer
> Pointer - integer
>
> Pointer - Pointer
>
> That is why pointer operator overloading is restricted.
Yes, I got that. I think I got confused. I thought one could have
pointer arguments but it seems there are restrictions. This:
T operator+(T &x, T *y)
is rejected but it can't conflict with normal pointer arithmetic, can
it?
>> What does the remark
>> "References can be replaced by arrays of length 1." mean?
>
> It means that if you write
>
> void function(T s[]);
>
> T s[1];
>
> The structure is always passed by reference. A hack surely,
> but a valid one.
I don't follow. That look like plain C. Where do references come in?
What has this to do woth operator overloading? The comment comes from
the middle of a table about permitted argument types.
--
Ben.