Hi everybody,
This topic was discussed once here, but... Why _cast() is called only for builtin data types? When I do: (int)something; then something->_cast("int") gets called, but when I do (SomeType)something; then SomeType(something) gets called? I just can't understand why, it seems a bit unlogical (if there is some logic behind - please explain). Additionally, there is no way to distinguish between regular constructor call and when type is casted... And concerning assignment operator overloading. I believe that this will be very useful feature, and it should not be [too] difficult to implement. Well, there will be some problems when target (lvalue) may have more than one type, but in case when it is not multi-type, it should be quite simple.
So... If, and only if, the object (class) defines `=() and ``=(), then: * If variable is of type SomeObject, and it is undefined, the function ``=() will be called and it should play constructor's role (we can't simply call constructor here since in this case we can't distinguish between regular constructor call and a call from assignment).
* If variable is defined and contains object of type SomeObject, then the function `=() will be called. When there is ambiguity, standard behavior should be used (or exception raised, or compiler error, etc). This way, IMHO, we can keep compatibility, and use very nice and useful feature same time. Any opinions, suggestions, idea, flames? :)
Regards, /Al
You are wrong. (SomeType)something; doesn't call SomeType with someting. (SomeType)(something) however does. If it was possible to cast things into arbitrtary types, how would you know if (SomeType)(something) really means SomeType(something) or (SomeType)something?
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 04:22: Subject: Implicit class construction, _cast() and `=()
Hi everybody,
This topic was discussed once here, but...
Why _cast() is called only for builtin data types? When I do:
(int)something;
then something->_cast("int") gets called, but when I do
(SomeType)something;
then SomeType(something) gets called? I just can't understand why, it seems a bit unlogical (if there is some logic behind - please explain). Additionally, there is no way to distinguish between regular constructor call and when type is casted...
And concerning assignment operator overloading. I believe that this will be very useful feature, and it should not be [too] difficult to implement. Well, there will be some problems when target (lvalue) may have more than one type, but in case when it is not multi-type, it should be quite simple.
So... If, and only if, the object (class) defines `=() and ``=(), then:
If variable is of type SomeObject, and it is undefined, the function ``=() will be called and it should play constructor's role (we can't simply call constructor here since in this case we can't distinguish between regular constructor call and a call from assignment).
If variable is defined and contains object of type SomeObject, then the function `=() will be called.
When there is ambiguity, standard behavior should be used (or exception raised, or compiler error, etc).
This way, IMHO, we can keep compatibility, and use very nice and useful feature same time.
Any opinions, suggestions, idea, flames? :)
Regards, /Al
/ Brevbäraren
On Tue, May 06, 2003 at 03:00:06PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
You are wrong. (SomeType)something; doesn't call SomeType with someting.
It does:
Pike v7.4 release 10 running Hilfe v3.5 (Incremental Pike Frontend)
class SomeType { void create(mixed ... args) { write("SomeType(%O)\n", args); } void _cast(mixed ... args) { write("SomeType_cast(%O)\n", args); } }; int x = 5; string y = "13"; (SomeType)x;
SomeType(({ /* 1 element */ 5 })) (1) Result: HilfeInput()->SomeType()
(SomeType)y;
SomeType(({ /* 1 element */ "13" })) (2) Result: HilfeInput()->SomeType()
(SomeType)(x);
SomeType(({ /* 1 element */ 5 })) (3) Result: HilfeInput()->SomeType()
(SomeType)(y);
SomeType(({ /* 1 element */ "13" })) (4) Result: HilfeInput()->SomeType()
So I am right :)
(SomeType)(something) however does.
As you can see - both do.
If it was possible to cast things into arbitrtary types, how would you know if (SomeType)(something) really means SomeType(something) or (SomeType)something?
I know because (TypeName) is a typecast operator. Type (class) name by itself is not used. So, the construct (SomeType)someobj must actually call someobj->_cast("SomeType") (as it does in case of simple types).
At least, this is logical. Or? :)
Regards, /Al
So I am right :)
No, you are not. Hilfe is an simulation of Pike, and is not always correct. Write the code in a stand alone file and see what you get.
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 15:42: Subject: Re: Implicit class construction, _cast() and `=()
On Tue, May 06, 2003 at 03:00:06PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
You are wrong. (SomeType)something; doesn't call SomeType with someting.
It does:
Pike v7.4 release 10 running Hilfe v3.5 (Incremental Pike Frontend)
class SomeType { void create(mixed ... args) { write("SomeType(%O)\n", args); } void _cast(mixed ... args) { write("SomeType_cast(%O)\n", args); } }; int x = 5; string y = "13"; (SomeType)x;
SomeType(({ /* 1 element */ 5 })) (1) Result: HilfeInput()->SomeType()
(SomeType)y;
SomeType(({ /* 1 element */ "13" })) (2) Result: HilfeInput()->SomeType()
(SomeType)(x);
SomeType(({ /* 1 element */ 5 })) (3) Result: HilfeInput()->SomeType()
(SomeType)(y);
SomeType(({ /* 1 element */ "13" })) (4) Result: HilfeInput()->SomeType()
So I am right :)
(SomeType)(something) however does.
As you can see - both do.
If it was possible to cast things into arbitrtary types, how would you know if (SomeType)(something) really means SomeType(something) or (SomeType)something?
I know because (TypeName) is a typecast operator. Type (class) name by itself is not used. So, the construct (SomeType)someobj must actually call someobj->_cast("SomeType") (as it does in case of simple types).
At least, this is logical. Or? :)
Regards, /Al
/ Brevbäraren
On Tue, May 06, 2003 at 04:00:02PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
No, you are not. Hilfe is an simulation of Pike, and is not always correct. Write the code in a stand alone file and see what you get.
Strange. Really, I see no difference between (int)something and (SomeType)something (logically), so why it is incorrect in last case?
Regards, /Al
int is a reserved word while SomeType is not. Note that it is not certain that SomeType is yet defined when we get "(SomeType)", so we can't assume that it is a cast.
mixed foo() { return (SomeType)"world"; }
constant SomeType = "Hello ";
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 18:33: Subject: Re: Implicit class construction, _cast() and `=()
On Tue, May 06, 2003 at 04:00:02PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
No, you are not. Hilfe is an simulation of Pike, and is not always correct. Write the code in a stand alone file and see what you get.
Strange. Really, I see no difference between (int)something and (SomeType)something (logically), so why it is incorrect in last case?
Regards, /Al
/ Brevbäraren
Thus with the current parser it'd be necessary to write
(object(SomeType)) my_object;
But the _cast lfun ought to be extended to get called here too.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-05-06 18:38: Subject: Re: Implicit class construction, _cast() and `=()
int is a reserved word while SomeType is not. Note that it is not certain that SomeType is yet defined when we get "(SomeType)", so we can't assume that it is a cast.
mixed foo() { return (SomeType)"world"; }
constant SomeType = "Hello ";
/ Martin Nilsson (lambda)
The name is cast, not _cast.
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 18:48: Subject: Re: Implicit class construction, _cast() and `=()
Thus with the current parser it'd be necessary to write
(object(SomeType)) my_object;
But the _cast lfun ought to be extended to get called here too.
/ Martin Stjernholm, Roxen IS
I've noticed similar compiler issues on several occasions. Example:
class BaseNode { static Element|Doc parent; Element|Doc getParent() { return parent; } // using class names as types works fine in the two lines above... int getDepth() { object(Element)|object(Doc) p; // ...but triggered a parse error if done here return ( p = this->getParent() ) ? ( p->getDepth() + 1 ) : -1; } /* ...more stuff elided */ }
also, soft casts such as [Element]p fail to parse, while [object(Element)]p or even [array(Element|Text)]children work OK.
/ rjb
Previous text:
2003-05-06 18:48: Subject: Re: Implicit class construction, _cast() and `=()
Thus with the current parser it'd be necessary to write
(object(SomeType)) my_object;
But the _cast lfun ought to be extended to get called here too.
/ Martin Stjernholm, Roxen IS
Yes. That's a limitation in the current grammar. Grubba and I have discussed it quite a bit and found that it's fairly complicated to fix (but possible). Grubbas new compiler should handle it properly.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-05-06 23:10: Subject: Re: Implicit class construction, _cast() and `=()
I've noticed similar compiler issues on several occasions. Example:
class BaseNode { static Element|Doc parent; Element|Doc getParent() { return parent; } // using class names as types works fine in the two lines above... int getDepth() { object(Element)|object(Doc) p; // ...but triggered a parse error if done here return ( p = this->getParent() ) ? ( p->getDepth() + 1 ) : -1; } /* ...more stuff elided */ }
also, soft casts such as [Element]p fail to parse, while [object(Element)]p or even [array(Element|Text)]children work OK.
/ rjb
I think the cast lfun interface has to be expanded a bit as well. If we do (A)B then the cast method in B should get the program A as second argument, I think. Further, if B has no cast method, should some ``cast (or even create) in A be called? Example: (Gmp.mpz)5 would then result in Gmp.mpz(5).
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 15:42: Subject: Re: Implicit class construction, _cast() and `=()
On Tue, May 06, 2003 at 03:00:06PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
You are wrong. (SomeType)something; doesn't call SomeType with someting.
It does:
Pike v7.4 release 10 running Hilfe v3.5 (Incremental Pike Frontend)
class SomeType { void create(mixed ... args) { write("SomeType(%O)\n", args); } void _cast(mixed ... args) { write("SomeType_cast(%O)\n", args); } }; int x = 5; string y = "13"; (SomeType)x;
SomeType(({ /* 1 element */ 5 })) (1) Result: HilfeInput()->SomeType()
(SomeType)y;
SomeType(({ /* 1 element */ "13" })) (2) Result: HilfeInput()->SomeType()
(SomeType)(x);
SomeType(({ /* 1 element */ 5 })) (3) Result: HilfeInput()->SomeType()
(SomeType)(y);
SomeType(({ /* 1 element */ "13" })) (4) Result: HilfeInput()->SomeType()
So I am right :)
(SomeType)(something) however does.
As you can see - both do.
If it was possible to cast things into arbitrtary types, how would you know if (SomeType)(something) really means SomeType(something) or (SomeType)something?
I know because (TypeName) is a typecast operator. Type (class) name by itself is not used. So, the construct (SomeType)someobj must actually call someobj->_cast("SomeType") (as it does in case of simple types).
At least, this is logical. Or? :)
Regards, /Al
/ Brevbäraren
On Tue, May 06, 2003 at 04:10:02PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
argument, I think. Further, if B has no cast method, should some ``cast (or even create) in A be called? Example: (Gmp.mpz)5 would then result in Gmp.mpz(5).
Not a good idea, IMHO. We need two constructors, then - one usual (called like SomeType()) and one - specially for casting purposes. Say, _create()? It would simplify things a lot.
But definitely, construct like (SomeType)variable should work exactly like (int)variable :)
Regards, /Al
No, we don't need another constructor. Using create is enough. We just define that A(B) is the same operation as (A)B. If the A class needs more than one parameter we can't cast to it anyway, and we'll get a compilation error. If B can't be used as input parameter to A we'll get a compilation error due to type incompatibilities.
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 18:36: Subject: Re: Implicit class construction, _cast() and `=()
On Tue, May 06, 2003 at 04:10:02PM +0200, Martin Nilsson (lambda) @ Pike (-) developers forum wrote:
argument, I think. Further, if B has no cast method, should some ``cast (or even create) in A be called? Example: (Gmp.mpz)5 would then result in Gmp.mpz(5).
Not a good idea, IMHO. We need two constructors, then - one usual (called like SomeType()) and one - specially for casting purposes. Say, _create()? It would simplify things a lot.
But definitely, construct like (SomeType)variable should work exactly like (int)variable :)
Regards, /Al
/ Brevbäraren
I think the cast lfun interface has to be expanded a bit as well. If we do (A)B then the cast method in B should get the program A as second argument, I think.
I agree.
Further, if B has no cast method, should some ``cast (or even create) in A be called? Example: (Gmp.mpz)5 would then result in Gmp.mpz(5).
I don't think it's a good idea to reuse the create lfun for that since that'd mean create() could be used in a situation the class author probably didn't expect. A right-cast operator lfun seems like a logical extension, though. The best would be if proper static functions are implemented so that
(A) b
is tried as the equivalent of
A.``cast (b)
and not
(tmp = A(), tmp->``cast (b), tmp)
That would allow ``cast to return an existing object.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-05-06 16:08: Subject: Re: Implicit class construction, _cast() and `=()
I think the cast lfun interface has to be expanded a bit as well. If we do (A)B then the cast method in B should get the program A as second argument, I think. Further, if B has no cast method, should some ``cast (or even create) in A be called? Example: (Gmp.mpz)5 would then result in Gmp.mpz(5).
/ Martin Nilsson (lambda)
I don't agree fully. I kind of like that the create would be reused, and see few real problems with it. The biggest concern is what to do with old classes in existing modules that one would like to be possible to cast to. It is also of course good to be able to explicitly declare that you allow an object to be casted to.
If we do use a ``cast method (there must be a better name available) I agree it should work as you say. One win here is the possibility to return an already existing object, as you say, but that isn't really that closely linked to this issue. I think that the possibility to somehow return an already existing object from the create method should be considered. I have missed that on some occasions. It would if nothing else make the implementation of a singleton class easy.
/ Martin Nilsson (lambda)
Previous text:
2003-05-06 23:20: Subject: Re: Implicit class construction, _cast() and `=()
I think the cast lfun interface has to be expanded a bit as well. If we do (A)B then the cast method in B should get the program A as second argument, I think.
I agree.
Further, if B has no cast method, should some ``cast (or even create) in A be called? Example: (Gmp.mpz)5 would then result in Gmp.mpz(5).
I don't think it's a good idea to reuse the create lfun for that since that'd mean create() could be used in a situation the class author probably didn't expect. A right-cast operator lfun seems like a logical extension, though. The best would be if proper static functions are implemented so that
(A) b
is tried as the equivalent of
A.``cast (b)
and not
(tmp = A(), tmp->``cast (b), tmp)
That would allow ``cast to return an existing object.
/ Martin Stjernholm, Roxen IS
Take for instance String.Buffer. It has a create function that takes the size as an integer, not a string as initial content. So the expression
(object(String.Buffer)) 17;
would not return a String.Buffer object representing the integer 17 in any reasonable sense. Therefore it'd only be a source of confusion to allow that syntax. There are many create functions like this one.
I think that the possibility to somehow return an already existing object from the create method should be considered.
Yes, it's a somewhat unrelated issue. If proper staticness is implemented then a sane extension is to allow create() to be declared properly static, in which case it would be expected to return the object to use.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-05-06 23:33: Subject: Re: Implicit class construction, _cast() and `=()
I don't agree fully. I kind of like that the create would be reused, and see few real problems with it. The biggest concern is what to do with old classes in existing modules that one would like to be possible to cast to. It is also of course good to be able to explicitly declare that you allow an object to be casted to.
If we do use a ``cast method (there must be a better name available) I agree it should work as you say. One win here is the possibility to return an already existing object, as you say, but that isn't really that closely linked to this issue. I think that the possibility to somehow return an already existing object from the create method should be considered. I have missed that on some occasions. It would if nothing else make the implementation of a singleton class easy.
/ Martin Nilsson (lambda)
Do you mean that this:
SomeObject o; ... o = 17;
should be rewritten to:
SomeObject o = <magic unassigned value>; ... if (o == <magic unassigned value>) o = SomeObject(); o->`= (17);
? If so, I have two objections:
1. The runtime overhead to check for the magic unassigned value before essentially every assignment is a bit too expensive for this feature.
2. Assignment operates on the variable, not the value in it. That's a sound rule which overall makes it a lot easier to reason about variables and values. If it's violated we'll probably get odd bugs which will be variants of this example I gave a while back:
object x = a_fishy_object; ... x = a_nice_object; if (x->is_fishy_object) { werror ("Foo?\n"); x = 0; // Begone! if (objectp (x) && x->is_fishy_object) { werror ("Arrgh!\n"); destruct (x); // Die, sucker! } }
In which situation would it be really useful to have an assignment operator? Would you be able to control it? I mean, even if you're aware that you're handling an object that behaves as above, wouldn't you find it difficult to not be able to assign values to the variables themselves?
/ Martin Stjernholm, Roxen IS
Previous text:
2003-05-06 04:22: Subject: Implicit class construction, _cast() and `=()
Hi everybody,
This topic was discussed once here, but...
Why _cast() is called only for builtin data types? When I do:
(int)something;
then something->_cast("int") gets called, but when I do
(SomeType)something;
then SomeType(something) gets called? I just can't understand why, it seems a bit unlogical (if there is some logic behind - please explain). Additionally, there is no way to distinguish between regular constructor call and when type is casted...
And concerning assignment operator overloading. I believe that this will be very useful feature, and it should not be [too] difficult to implement. Well, there will be some problems when target (lvalue) may have more than one type, but in case when it is not multi-type, it should be quite simple.
So... If, and only if, the object (class) defines `=() and ``=(), then:
If variable is of type SomeObject, and it is undefined, the function ``=() will be called and it should play constructor's role (we can't simply call constructor here since in this case we can't distinguish between regular constructor call and a call from assignment).
If variable is defined and contains object of type SomeObject, then the function `=() will be called.
When there is ambiguity, standard behavior should be used (or exception raised, or compiler error, etc).
This way, IMHO, we can keep compatibility, and use very nice and useful feature same time.
Any opinions, suggestions, idea, flames? :)
Regards, /Al
/ Brevbäraren
pike-devel@lists.lysator.liu.se