Type checking with local variable and a value type

Hello,
This has been tested with .NET 5.

In C#, there exists the following:

if (Value is String s)
{
  // can use the s variable
}

In Oxygene, we can use (and it works):

with matching s := String (Value) do begin
  //  can use the s variable
end;

The problem is when trying to use a value type.

The following runs in C#:

if (Value is Int32 s)
{
  // can use the s variable
}

The same construct generates an InvalidCastException in Oxygene:

with matching s := Int32 (Value) do begin
  //  can use the s variable
end;

EDIT: corrected the Oxygene example, as per the third message.

UP: no answer!

Hmm, I think this is as designed. since value types cant be null, I believe the () cast does the same as as — raise an exception, since it’s can’t really return nil…

with s := nullable Int32(Value) do begin

might work?

nullable Int32 works but it makes a conversion from Int32 to nullable Int32.

I’ve made a little error in my first post: the equivalent in Oxygene is:

with matching s := String (Value) do begin
  //  can use the s variable
end;

but it still generates an InvalidCastException with values types.

What would be nice is if the compiler can generate the following.

Reference type

var s := String (value);
if assigned (s) then
  ...

Value type

if Value is Int32 then begin
  var s := Int32 (Value;
  ...
end;

A nice addition would be also for the case type construct, as in C#:

case Value type of
  var s : String : ;  // can use local variable s as a String
  var i : Int32 :  ;  // can use local variable i as an Int32
end;

Well, you cant have your cake and eat it too :).

What is Int32(Value) supposed to give you? if the result is supposed to be an integer, all it can to is fail (or return 0, with would be worse/really wrong)… If yu want to get back a potential null value, you have to use nullable.

That’s why I corrected the example with matching, so it should make sense then, no?

well, those a re two entirely separate languages constructs

with matching NEW_VARIABLE := ANY_EXPRESSION do

will run the statement if NEW_VARIABLE is non-null. the with statement has no understanding of ANY_EXPRESSION, nor can (or should) int affect how that expression works

with matching s := Int32(Value) do begin
  //  can use the s variable
end;

is literally there exact same thing as

var s := Int32(Value);
if assigned(s) then begin
  //  can use the s variable
end;

and it cannot change what “Int32(Value)” does.

So, if you prefer, provide a new syntax that let us check the type of a value and assign it to a variable of the right type…

As with matching doesn’t work for nullable types, I thought it was a good solution for the syntax.

Yes, we’d have to port over the mess that is C#'s patterns. Not sure if we want to do that to Oxygene, but I’ll bring it up for internal discussion.

What is more readable?

if Value is Int32 then begin
  var i := Int32 (Value);
  ...
end;

or

with matching i := Int32 (Value) do begin
end;

And for the case type:

case Value type of
  typeOf (Int32) : begin
    var i := Int32 (Value);
    ...
  end;

or

case Value type of
  var i : Int32 : begin  // or "i as Int32"
  end;
end;

not his, for sure, IMHO.

Perhaps with lambda expressions:

case Value type of
  typeOf (Int32) : i -> ...  // with begin...end for multi statements
end;