(Dang. Wordy post, and almost completely unrelated to my proposal.)
I guess I'd be in favor of it, but yet I'm not terribly excited about it. I wonder why...
Casting is unfortunately an often useless and ill designed feature in Pike; that might account for some of the dispassion. You can only cast to primitive types, and value casts don't necessarily work, even if you know a value to be a string and want to cast it to an int, when declared a string|int. It's a system difficult to grow incrementally better too, unfortunately.
Even though in some ways it's a syntactically very powerful operation on recursively casting a large data structure into another, using compound type casts like (array(string)). It just doesn't reach do all that much more, when you don't primarily work with primitive types.
I'm not really bashing the lack of design in Pike; its evolved nature is what makes it good, too. But casts, at least to me, feel a bit like a dead end.
The thought crept up on me after reading The Pinocchio Problem, http://steve-yegge.blogspot.com/2007/01/pinocchio-problem.html -- while not technically dead code, pike and casting feels like it has hit an evolutionary dead end. Small convenience changes like the one suggested might be within reach, but order of magnitude improvements are out of reach. With a bit of luck I just might know too little of pike's internals to be right about this.
On Sat, Jan 20, 2007 at 06:30:00AM +0000, Johan Sundstr�m (Achtung Liebe!) @ Pike (-) developers forum wrote:
Casting is unfortunately an often useless and ill designed feature in Pike; that might account for some of the dispassion. You can only cast to primitive types, and value casts don't necessarily work, even if you know a value to be a string and want to cast it to an int, when declared a string|int.
oh, that is new to me. could you elaborate these points with some examples
not being able to cast to object types is clear, but where does casing string|int to int not work as expected? and what is ill designed about it all?
greetings, martin.
Casting is unfortunately an often useless and ill designed feature in Pike; that might account for some of the dispassion. You can only cast to primitive types, and value casts don't necessarily work, even if you know a value to be a string and want to cast it to an int, when declared a string|int. It's a system difficult to grow incrementally better too, unfortunately.
I think you will have to exemplify a bit. Generally I think casts should be used sparingly in any language with some sort of typeing, and I don't think adding more complex casts would really improve things in Pike. Some examples that illustrate why it would be nice could perhaps sway me though.
I agree, when discussing type casts. Value casts, as I am focused on, is a rather different story. The field is sort of mudded up in pike, as the workings of the type system isn't all that obvious to the naked eye.
If we instead discuss it in terms of data representation conversion, or data type conversion, rather than type casting, we significantly disambiguate and unmuddle things.
In Pike, data type conversion is typically handled completely by whatever type of object is being converted to, with no help from the object being converted from. This is done in create(), and to convert an array of integers treated as time_t seconds-since-the-Epoch, into Calendar.Second objects, for instance, we can't employ any help from the pike's cast LFUNs -- (array(Calendar.Second))integers -- but have to resort to map( integers, Calendar.Second ), or the (very brittle) automap syntax Calendar.Second( integers[*] ), which I personally avoid even in those very basic cases where it actually works (like this).
I do data type conversion a lot, especially near database operations persisting or reading back objects from storage. Having largely been away from pike hackery for a while, found the lack of language support for it, if not surprising (I'm not new to pike), then at least not a pleasant feature hole to rediscover.
I do consider pike's array value casting a very elegant and readable higher order operation. It's just painfully limited in scope. A lot like automap, actually. :-)
In Pike, data type conversion is typically handled completely by whatever type of object is being converted to, with no help from the object being converted from. This is done in create(), and to convert an array of integers treated as time_t seconds-since-the-Epoch, into Calendar.Second objects, for instance, we can't employ any help from the pike's cast LFUNs -- (array(Calendar.Second))integers -- but have to resort to map( integers, Calendar.Second ), or the (very brittle) automap syntax Calendar.Second( integers[*] ), which I personally avoid even in those very basic cases where it actually works (like this).
The above paragraph doesn't make any sense unless you swap "to" and "from" in the first sentence.
I do data type conversion a lot, especially near database operations persisting or reading back objects from storage. Having largely been away from pike hackery for a while, found the lack of language support for it, if not surprising (I'm not new to pike), then at least not a pleasant feature hole to rediscover.
I don't see how your suggested change for the cast() operator to falling back to _sprintf would help anything in your example case.
I don't see how your suggested change for the cast() operator to falling back to _sprintf would help anything in your example case.
It wasn't. I probably should have changed topics/subjects rather than just noting it as below, two or three posts up the thread:
(Dang. Wordy post, and almost completely unrelated to my proposal.)
In Pike, data type conversion is typically handled completely by whatever type of object is being converted to, with no help from the object being converted from. [...]
The above paragraph doesn't make any sense unless you swap "to" and "from" in the first sentence.
Not really, when we are talking about objects. With primitive types, you are right. Example: a Foo object gets converted to a Bar object;
Foo f = Foo(); Bar b = Bar( f );
Object Bar's create gets passed something used to initialize itself into whatever it knows how to deduce from the passed parameter. Bar gets no help from Foo, except possibly by casting Foo to primitive types of some sort. If we could get Foo's help, we would have
Bar b = (Bar)f;
calling f->cast, which would be delegated the work of creating a Bar object, based on its own state.
But I'm afraid I don't have any constructive thoughts on how to do something like that. I believe Nilsson tried skewing reality that way at one time, but largely didn't end up anywhere better than where we were and let it be as is instead (or was reverted, if it got further).
I unfortunately don't recall what the details were. Would something along the lines above be possible to do with today's type system with modest effort?
pike-devel@lists.lysator.liu.se