hhvm / user-documentation

Documentation for those that use HHVM and write Hack code.
http://docs.hhvm.com/
Other
129 stars 159 forks source link

Not enough info on the difference between BuiltinEnum::coerce and as/?as #1368

Open alexeyt opened 4 months ago

alexeyt commented 4 months ago

Please complete the information below:

Where is the problem?

https://docs.hhvm.com/hack/built-in-types/enum#is--as

What is the problem?

It says The operators is and as/?as behave similarly, but not exactly, to isValid() (similar to is) and assert()/coerce() (similar to as/?as) but does not explain what the difference in behavior is. The difference between coerce and as/?as is very important when values of the 'opposite' arraykey type to the base type of the enum may be present; for example:

<?hh

enum MyIntEnum: int {
   ZERO = 0;
   ONE = 1;
}

enum MyStringEnum: string {
  ZERO = '0';
  ONE = '1';
}

<<__EntryPoint>> function main(): void {
  echo "string values, int enum\n";
  var_dump(
    MyIntEnum::coerce('1'),
    '1' as MyIntEnum,
    '1' ?as MyIntEnum,
  );
  var_dump(
    MyIntEnum::ONE is int,
    '1' as MyIntEnum is int,
  );

  echo "int values, string enum\n";
  var_dump(
    MyStringEnum::coerce(1),
    1 as MyStringEnum,
    1 ?as MyStringEnum,
  );
  var_dump(
    MyStringEnum::ONE is string,
    1 as MyStringEnum is string,
  );
}

produces

string values, int enum
int(1)
string(1) "1"
string(1) "1"
bool(true)
bool(false)
int values, string enum
string(1) "1"
int(1)
int(1)
bool(true)
bool(false)

In light of this the wording Caution: These operators may perform implicit int/string coercion of enum values to preserve compatibility with isValid() seems potentially deceptive as well - when I first read it I assumed that the result of as/?as may be a different type from the input (what ::coerce() does). In reality coercion is done when checking if the value is compatible with the enum only; if it is then as/?as will pass it through un-coerced.


Please don't change anything below this point.