Draco-lang / Language-suggestions

Collecting ideas for a new .NET language that could replace C#
75 stars 5 forks source link

Conversion to object must be explicit #68

Open jl0pd opened 2 years ago

jl0pd commented 2 years ago

System.Object is a root of type hierarchy in dotnet and all mainstream languages (C#, F#, VB) allows implicit upcasting to parent types. I agree with implicit conversion to base type, but object should be exception, that won't be allowed to implicitly converted.

There are some examples

Object.ReferenceEquals(1, 1) // false
Object.ReferenceEquals("q", 1) // false. This should not have compiled, but it's allowed
object PerformComputation(int a, int b)
{
    return a + b; // implicit boxing, always produces new object
}

object PerformComputation(int a, int b)
{
    return GetBoxed(a + b); // boxing is explicit, potentially returning cached value
}
void M(float a) { }
void M(object a) { }
void Foo() => M(5.0); // calls M(object)

Real world example: WPF's UncommonField<T>.SetValue boxes both input value and _defaultValue on each call, while it could perform better. It was fixed only in net7 timeline

LPeter1997 commented 2 years ago

I like the examples you brought, they show some big pitfalls of boxing. Regarding that, I wonder if making only boxing explicit would be enough to avoid these mistakes, or is it also significantly dangerous to allow implicit upcasting of reference types?

jl0pd commented 2 years ago

Implicit upcasting of reference types should be allowed, since it's a basis of polymorphism. Requirement of casting to base type may quickly become annoying and will neglect value of this proposal, because people will just always think "alright, insert casting again". So I think that conversion of reference types to it's parent or interface still should be implicit, with exception of object. Not sure about conversion of struct to interface

LPeter1997 commented 2 years ago

So I think that conversion of reference types to it's parent or interface still should be implicit, with exception of object.

Yes, sorry, I wasn't clear enough with my comment. It was about if we should disallow the implicit upcasting of reference types to object too, since your examples were built around issues with boxing specifically. Is it as dangerous as boxing?

jl0pd commented 2 years ago

Yeah, it's still dangerous, even with reference types:

Client client = ...;
Order order = makeOrder(client);
client.Equals(order);

This will compile, even though it doesn't make any sense to do such operation (comparing models of different types)

LPeter1997 commented 2 years ago

Fair, the ancient pre-generics APIs could be a pitfall.

svick commented 2 years ago

This is a weird idea, but maybe the language could hide object.Equals(object) on any type that is not object itself?

I feel that requiring upcasting to be explicit because of a single method is a disproportionate response, so this might be an alternative solution.

LPeter1997 commented 2 years ago

Yeah this is why I semi-proposed explicit boxing instead, as that seems like a more logical addition to me. But other opinions would also be nice on this.