View Issue Details

IDProjectCategoryView StatusLast Update
0000072LDMud 3.5LPC Compiler/Preprocessorpublic2011-02-13 22:47
Reporterdan Assigned To 
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionsuspended 
PlatformGueldenland / LDMudOSFreeBSDOS Version3.2.11-dev.645
Summary0000072: clash between several features re. type-safety
DescriptionI'm not sure which of the following 'features' were present on LPmud, and I have no idea how the code below behaved on it, since I don't have access to a MUD not running on LDmud anymore.

1. Assignment operators ignore target type.

2. A function requiring its parameters to be of a certain type may be passed arguments of different types when called via call_other.

3. Casts of values to their own type at least generate a warning.

This leads to workarounds in the mudlib along the lines of:
void do_something_or_other(int x) {
    x = (int)(float)x; // cast any number to int, because
    x = x % 10; // modulo doesn't work on floats
}

The culprit in our case was code such as:
    int value;
    value *= 1.5;
    do_something_or_other(value);

It is also possible to assign any other type than int to value, and operators such as *= and /= will result in a value of type float if the rhs is of type float, and so on.

The calling expression is not allowed to explicitly cast the value it passes to the callee to int, because this would generate a warning.

Possible fixes:
- assignment operators should cast their result to the declared type of the target variable
- values should be cast to their declared type any time a variable is modified, direct assignment of an incompatible value should result in an error
- call_other could result in a runtime error on type mismatch
Steps To Reproduceint a = 3;
a *= 1.5;
printf("%O\n", a);
TagsNo tags attached.

Relationships

related to 0000666 resolvedzesstra RfC: Type-checking at run-time 

Activities

lars

2004-07-02 00:08

reporter   ~0000075

This behavior is historic: in the beginning LPC was a typeless language, and types were added over time. At runtime (which is when call_others are resolved and executed), all type information of the variables and parameters is lost.

The typechecking in the compiler also suffers from this in being spotty and incomplete.

The whole situation is kinda an ongoing defect :-)

However, for your mudlib, the proper solution is not to use casts like that, but to define the function properly:

void do_something_or_other (mixed x) {
     x = to_int(x); // cast any number to int, because
     x = x % 10; // modulo doesn't work on floats
 }
 
as casting of a value to its own type is usually a strong indication that the type declaration of the value is wrong in the first place.

dan

2004-07-02 02:45

reporter   ~0000078

Changing the argument type to mixed would make the function work, but it *is* meant to be an int, and it was only ever called with values believed to be ints because the variables that held them where declared int.

If I have to change the type of an argument, then cast it to the desired type, this is a serious flaw of the language. By this reasoning, I have to change *any* argument type to mixed because I can't ever be sure of the actual type of arguments that are passed ot the function.

I know of the historical origin of this problem, but at least LPMud never complained. The code in question did work too, though I'm not sure what it really did.

I'd much prefer the compiler to just add the cast by itself. No compile-time knowledge is required at run time.

menaures

2004-07-03 12:57

reporter   ~0000080

What you request is typechecking at runtime.

In my opinion, your "int value; value *= 1.5;" example should throw an error at compile time because of incompatible types (it does that already in 3.2.10-dev.616). As for the casting - there are many ways to skin a cat, and I don't like yours.

In my opinion, when a function gets passed parameters of the wrong type, that's an important error which shouldn't be hidden by a cast. I don't cast parameters, but rather check them like this and throw an error if necessary:

void foo(int x)
{
    if(!intp(x))
    {
        raise_error("Bad arg 1 to foo: not an int.\n");
    }
}

If the compiler did a cast here by itself like you want it to, checks like this one wouldn't work anymore. If Lars really wants to add such a feature, a lot more thought has to be put into this.

zesstra

2009-03-04 16:25

administrator   ~0000971

I agree with Menaures.
A comment to Lars suggestion: If you want to gracefully convert wrong argument types, you can still do:
void do_something_or_other (int x) {
     x = to_int(x); // cast any number to int, because
... }
There is no need to declare the argument 'mixed', if the function is not designed to receive anything other than int. But I usually prefer Menaures approach to raise an error.

There are the pragmas strict_types/strong_types in combination with save_types which solves quite a lot of these problems, because they can be detected at compile-time.

Concerning call_other/run-time type checking... First, a check is only possible if the type information is still available (without save_types it is discarded after compilation). But we could only introduce it optionally, because otherwise people start yelling at us and it introduces an additional overhead into function calls (maybe the run-time check might be restricted to all the inter-object calls). Let's discuss, if it worth it. :-)

zesstra

2011-02-13 22:47

administrator   ~0001967

If I don't overlook something here, this seems to be obsolete since we started to introduce the runtime type checks. They are not complete yet, but we hopefully get there in 3.5.x and this discussion seems to done.

Please tell me if you disagree.

Issue History

Date Modified Username Field Change
2004-06-30 05:06 dan New Issue
2004-07-02 00:08 lars Note Added: 0000075
2004-07-02 00:09 lars Status new => acknowledged
2004-07-02 00:09 lars Description Updated
2004-07-02 02:45 dan Note Added: 0000078
2004-07-03 12:57 menaures Note Added: 0000080
2004-12-29 02:34 lars Project LDMud 3.2-dev => LDMud
2009-03-04 16:25 zesstra Note Added: 0000971
2009-03-04 16:25 zesstra Status acknowledged => feedback
2009-03-04 16:26 zesstra Project LDMud => LDMud 3.5
2009-06-24 08:13 zesstra Relationship added related to 0000666
2011-02-13 22:47 zesstra Note Added: 0001967
2011-02-13 22:47 zesstra Status feedback => closed
2011-02-13 22:47 zesstra Resolution open => suspended