On Sat, Jun 22, 2024 at 10:53 PM Rowan Tommins [IMSoP] <imsop....@rwec.co.uk> wrote: > > On 22/06/2024 19:34, Robert Landers wrote: > > I've brought this up before, but I mostly see "as" being useful for > static analysis. That's what I've mostly used it for C#, anyway. > Logically, you know the type, but due to one-thing-or-another you > can't "prove" the type is that type (such as foreach-arrays or dealing > with results from user-code callbacks in library code). I want to be > able to say "this is an int or else." > > > I absolutely see the use case for that; I just don't think "as" is a good > word for it, because that's not what it means in normal English. > > > Incidentally, according to the C# docs at > https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator > > > The as operator explicitly converts the result of an expression to a given > > reference or nullable value type. If the conversion isn't possible, the as > > operator returns null. Unlike a cast expression, the as operator never > > throws an exception. > > So it more closely matches my intuition: a statement of just "foo as Bar;" > would be useless, because it's calculating a value and discarding it, with no > side effects.
In general, you assign the result of the operation so that the output is useful. Here's how that might look in PHP with the C# rules: function foo(BarInterface $bar) { $baz = $bar as Baz; $baz?->thing(); $bar->otherThing(); } With "is" then it looks a little more wonky but isn't far from the current instanceof method: function foo(BarInterface $bar) { if ( $bar is Baz ) $bar->thing(); $bar->otherThing(); } With fibers/async, "as" is actually more important than "is" (at least as far as crashing goes): class Foo { public BarInterface $bar; public function doStuff() { $baz = $this->bar as Baz; // some stuff with $baz callComplexThing(); // suspends current fiber, // $this->bar is no longer the same object // or concrete type when we return $baz->something(); } } If we were to do an "is" check on the first line, by the time the fiber is resumed, we've got a completely different type on our hands and it would crash. Maybe that is desirable, maybe not, but we know that we have a reference of the type we want and it won't be changed under us by using "as." > As you say, the conversion might not be of the value, but of the statically > analysed type, but in C#, that's all part of the language. In PHP "$foo = > $bar as SomeInterface;" would have no visible effect except in third-party > tooling, where it can already be written "/** @var SomeInterface $foo */ $foo > = $bar;" Hopefully my examples show how it can be useful (at least when it returns null if it is the wrong type). When it gives a TypeError or something, it becomes far less useful -- at least for the sake of conciseness. However, it becomes far more useful to dealing with scalar casts: function foo(int $type) {} foo(123.456 as int); // crashes foo(null as int); // crashes But even if we did return null, those would crash unless foo() took int|null, which may or may not be what you want ... With it always being an error if it doesn't match, it's really not that useful, as you point out. > > > -- > Rowan Tommins > [IMSoP]