On Fri, Aug 16, 2024, at 6:35 AM, Alexandru Pătrănescu wrote:
> Hi Nick,
>> 
>> Is there any interest in having enums as class constants?
>> 
>> I'm often finding cases where I would like to have an enum inside of a
>> class, but don't want a free-floating enum that's basically like
>> another class.
>> 
> 
> ...<snip>... 
> 
>> 
>> class SSHClient {
>> 
>>    public const enum CommandResult
>>    {
>>        case Success;
>>        case Failure;
>>        case Unknown;
>>        case Timeout;
>>    }
>> 
>>    // ...
>> }
>> 
>> 
>> // Usage:
>> 
>> SSHClient::CommandResult::Success
>
>
> I feel this topic could be maybe more broad and be called "nested 
> classes" that are already supported in multiple languages: Java, Swift, 
> Python, C#, C++, JavaScript, etc.
>
> The syntax you showed is usually identical with what other languages 
> use, except that probably the const is unnecessary.
> The nested class can have visibility as sometimes having it private 
> makes sense.
> Accessing it through `::` is probably fine, but a deeper look at the 
> grammar might be necessary.
> The nested class would have access to parent class private properties 
> and methods.
>
> I also mentioned this topic on the subject of defining a type in an 
> autoloader compatible way.
> And indeed, a type could also be defined nested in a class if we want 
> to support that as well.
>
> Now, this feature is not simple, and I think it needs proper 
> sponsorship from someone experienced with internals.
>
> Regards,
> Alex

I agree with Alexandru.  Since enums are 90% syntactic sugar over classes, 
"inner enums" would be 80% of the way to "inner classes".  And I would be in 
favor of inner classes. :-)  There's a lot of potential benefits there, but 
also a lot of edge cases to sort out regarding visibility, what is allowed to 
extend from what, etc.  But that would support inner enums as well.

Based on our sibling languages (Java, Kotlin, C#, etc.), the syntax would 
likely be something like:

class Outer
{
  private string $foo;

  public function __construct(protected Sort $order) {}

  enum Sort
  {
    case Asc;
    case Desc;
  }

  class Inner
  {
    public function __construct(private string $baz) {}
  }

  private class HIdden
  {
    public function __construct(private string $baz) {}
  }
}

Which enables:

$case = Outer::Sort::Asc;
$o = new Outer($case);

$i = new Outer::Inner('beep');

$h = new Outer::Hidden('beep'); // Visibility error

I would have to research to see if other languages did this, but one option 
would be to allow an inner class to extend an outer class even if it's final, 
which would essentially give us sealed classes for free:

final class Outer
{
  class InnerA extends Outer {}

  class InnerB extends Outer {}

  class InnerC extends Outer {}
}

// But this is still not OK:
class Sibling extends Outer {}

Note: I have no idea how difficult/complicated this would be, but I would be in 
favor of exploring it.

--Larry Garfield

Reply via email to