I'm brand new to Boo. I just wrote a program and was pleased with how easy it was to write. Then I added the last line to my program and was dismayed that a compile-time error was not generated. Looking at the IL, I see that it's type-casted to the variable type and will always fail at run time. Is this a bug, or by design? (code below)
namespace MyFirst
import System
class Fruit: [Property(Color)] color as string [Getter(Eaten)] eaten as bool
def Eat(): raise InvalidOperationException("Already eaten.") if eaten eaten = true
class Apple(Fruit): def constructor(): Color = "Red"
apple = Apple() apple.Eat() print apple.Color print apple.Eaten apple = Fruit() # This will always fail because apple is already an Apple, but Fruit is its base type
On 2/25/07, Andrew Arnott <andrewarn...@gmail.com> wrote:
> I'm brand new to Boo. I just wrote a program and was pleased with how > easy it was to write. Then I added the last line to my program and > was dismayed that a compile-time error was not generated. Looking at > the IL, I see that it's type-casted to the variable type and will > always fail at run time. Is this a bug, or by design? (code below) > [testcase]
Hi and welcome! :)
Yes this is a bug, from my understanding it is caused because TypeSystemServices.AreTypeRelated(left,right) always returns true because CanBeReachedByDownCastOrPromotion inverts the IsSubclassOf() test in such a way that an assignment is authorized whether left is subclass of right or vice-versa.
I'm not sure what is the goal of this method : "value type promotion" is ok but implicit downcast seems dangerous to me (?).
On 2/25/07, Cedric Vivier <cedr...@neonux.com> wrote:
> because CanBeReachedByDownCastOrPromotion inverts the IsSubclassOf() > test in such a way that an assignment is authorized whether left is > subclass of right or vice-versa.
s/IsSubclassOf()/IsAssignableFrom
but it is pretty much the same thing in this context ;)
On 2/26/07, Rodrigo B. de Oliveira <rodrigobam...@gmail.com> wrote:
> On 2/25/07, Cedric Vivier <cedr...@neonux.com> wrote: > > ... > > I'm not sure what is the goal of this method : "value type promotion" > > is ok but implicit downcast seems dangerous to me (?).
> That's by design.
Didn't know that. If this is by design shouldn't the compiler show a warning for this kind of downcasting then? In the code Andrew given as example, I assume in most cases the developer would have forgotten to force type of "apple" to Fruit, so wouldn't be better it is possible to catch this at compile-time instead of run-time.
Also, I may be naive but I always thought downcasting is bad practice and user code relying on it is bad design, or do I miss something? In which case(s) would this kind of downcasting be useful and actually work on the CLI ?
On 2/26/07, Cedric Vivier <cedr...@neonux.com> wrote:
> On 2/26/07, Rodrigo B. de Oliveira <rodrigobam...@gmail.com> wrote:
> > On 2/25/07, Cedric Vivier <cedr...@neonux.com> wrote: > > > ... > > > I'm not sure what is the goal of this method : "value type promotion" > > > is ok but implicit downcast seems dangerous to me (?).
> > That's by design.
> Didn't know that. If this is by design shouldn't the compiler show a > warning for this kind of downcasting then?
I'm not sure.
> In the code Andrew given as example, I assume in most cases the > developer would have forgotten to force type of "apple" to Fruit, so > wouldn't be better it is possible to catch this at compile-time > instead of run-time.
Consider the following example:
callable Handler(o as object)
class Dispatcher: def AddRoute(predicate as Predicate, handler as Handler): ... def Dispatch(o): ...
d = Dispatcher() d.AddRoute({ o | o isa string }) do (o): s as string = o print s.ToUpper()
d.Dispatch("very contrived example, that's for sure")
And the fact is that since boo allows downcasting, the handler could be abbreviated to:
d.AddRoute({ o | o isa string }) do (s as string): print s.ToUpper()
> Also, I may be naive but I always thought downcasting is bad practice > and user code relying on it is bad design, or do I miss something?
I agree that a language should encourage good design. I don't agree it should prevent "bad design".
> which case(s) would this kind of downcasting be useful and actually > work on the CLI ?
On 2/26/07, Rodrigo B. de Oliveira <rodrigobam...@gmail.com> wrote:
> d.Dispatch("very contrived example, that's for sure") > And the fact is that since boo allows downcasting, the handler could be > abbreviated to: > d.AddRoute({ o | o isa string }) do (s as string): > print s.ToUpper()
> > Also, I may be naive but I always thought downcasting is bad practice > > and user code relying on it is bad design, or do I miss something?
> I agree that a language should encourage good design. I don't agree it > should prevent "bad design".
Sure I agree on this, language flexibility is good - else we would all be more than happy with Java's baby-sit-typing, checked exceptions and all the goodness ;) - but I also believe a compiler should warn of "bad design" when it comes to potentially dangerous/breaker code instead of doing this kind of dangerous things in the back of the developer.
As a developer I wouldn't like to have some large server application written in Boo break overnight because of some rarely-called method* containing such a simple coding mistake as in Andrew's example (forgot to force type inference - or maybe to use duck in other situations - on a thus later downcasted object).
After reading your example I can now grasp useful/working cases of downcasting only in some "contrived" situations, if there is not more general cases, aren't we making a reverse-generalization here by privileging the special case instead of making sure the general case is "under (developer's) control" ?
*: in a ideal world there would be a test suite covering the method and the server would have a nice exception handling fallback but well it's an example for debate's sake! ;-)
> On 2/26/07, Cedric Vivier <cedr...@neonux.com> wrote:
> > On 2/26/07, Rodrigo B. de Oliveira <rodrigobam...@gmail.com> wrote:
> > > On 2/25/07, Cedric Vivier <cedr...@neonux.com> wrote: > > > > ... > > > > I'm not sure what is the goal of this method : "value type promotion" > > > > is ok but implicit downcast seems dangerous to me (?).
> > > That's by design.
> > Didn't know that. If this is by design shouldn't the compiler show a > > warning for this kind of downcasting then?
> I'm not sure.
> > In the code Andrew given as example, I assume in most cases the > > developer would have forgotten to force type of "apple" to Fruit, so > > wouldn't be better it is possible to catch this at compile-time > > instead of run-time.
> Consider the following example:
> callable Handler(o as object)
> class Dispatcher: > def AddRoute(predicate as Predicate, handler as Handler): > ... > def Dispatch(o): > ...
> d = Dispatcher() > d.AddRoute({ o | o isa string }) do (o): > s as string = o > print s.ToUpper()
> d.Dispatch("very contrived example, that's for sure")
> And the fact is that since boo allows downcasting, the handler could be > abbreviated to:
> d.AddRoute({ o | o isa string }) do (s as string): > print s.ToUpper()
> > Also, I may be naive but I always thought downcasting is bad practice > > and user code relying on it is bad design, or do I miss something?
> I agree that a language should encourage good design. I don't agree it > should prevent "bad design".
> > which case(s) would this kind of downcasting be useful and actually > > work on the CLI ?
> But this feature is also a potential source of bugs... Maybe, > compromise is to allow downcasting from "object" type only?
I don't think this would change much to the problem and this would certainly diminish flexibility as Rodrigo pointed out. As said above I believe we should just emit a warning/notice to make sure the developer knows what he is doing here (such as he can change the code directly if this not the wanted behavior).
On 2/26/07, Cedric Vivier <cedr...@neonux.com> wrote:
> On 2/26/07, az <al.z...@gmail.com> wrote: > > But this feature is also a potential source of bugs... Maybe, > > compromise is to allow downcasting from "object" type only?
> I don't think this would change much to the problem and this would > certainly diminish flexibility as Rodrigo pointed out. > As said above I believe we should just emit a warning/notice to make > sure the developer knows what he is doing here (such as he can change > the code directly if this not the wanted behavior).
Another option may be to emit warning/notice only when *not* downcasting from object since this is probably the most common use of downcasting so most people using this feature won't see warnings at all, and type safety paranoids would not be using object in the first place anyway :-) In this setup the warning/notices would be displayed only where there is a real risk of a coding mistake imo.
> >> apple = Fruit() # This will always fail because apple is already an > Apple, but Fruit is its base type > In the code Andrew given as example, I assume in most cases the > > developer would have forgotten to force type of "apple" to Fruit, so > > wouldn't be better it is possible to catch this at compile-time > > instead of run-time.
I agree. If code will always fail, there should at least be a warning, but I guess this would require a check in the compiler for this specific kind of case. Personally I would have preferred if boo required some explicit indicator of a downcast, e.g.
a as Apple, b as Fruit a := b // ":=" for "cast equals" a ?= b // or maybe this syntax... but what makes me think // that this means "a = b as Apple" in some other language?
This is still wrist friendly, so I'd say it meets boo's main design idea (unlike, say, the cast() pseudo-function...) -- - David http://qism.blogspot.com