azjezz / psl

📚 PHP Standard Library - a modern, consistent, centralized, well-typed, non-blocking set of APIs for PHP programmers
MIT License
1.2k stars 69 forks source link

add `Vec\get`, `Vec\get_typed`, `Dict\get` and `Dict\get_typed` functions. #374

Open azjezz opened 1 year ago

azjezz commented 1 year ago

API:

namespace Psl\Dict {
  use Psl\Type;
  use Psl\Option;
  use Psl\Iter;

  function get<Tk, Tv>(dict<Tk, Tv> $d, Tk $k): Option\Option<Tv> {
    return Iter\contains_key($d, $k) ? Option\some($d[$k]) : Option\none();
  }

  function get_typed<T>(dict<array-key, mixed> $d, array-key $k, Type\TypeInterface<T> $t): Option\Option<T> {
    return Iter\contains_key($d, $k) ? Option\some($t->coerce($d[$k])) : Option\none();
  }
}

namespace Psl\Vec {
  use Psl\Type;
  use Psl\Option;
  use Psl\Iter;

  function get<T>(vec<T> $v, int $k): Option\Option<T> {
    return Iter\contains_key($v, $k) ? Option\some($v[$k]) : Option\none();
  }

  function get_typed<T>(vec<mixed> $v, int $k, Type\TypeInterface<T> $t): Option\Option<T> {
    return Iter\contains_key($v, $k) ? Option\some($t->coerce($v[$k])) : Option\none();
  }
}
azjezz commented 1 year ago

@veewee what do you think about this? could be really useful for chaining :)

Dict\get($arr, "foo")
  ->then(fn($value) => ...)
  ->then(fn($value) => ...)
  ->then(fn($value) => ...);
veewee commented 1 year ago

would be lovely indeed! The typed one would throw a coerce exception? Is that intended?

Where do you draw the line in consistency? Since other functions currently return nullables?

In an ideal world, we wouldnt have to deal with nulls in PSL...

azjezz commented 1 year ago

hm, returning none for invalid type would be a weird, and might be confusing, i think we can start by adding get and leave get_typed for later.

veewee commented 1 year ago

The typed version could return Option<Result<T>> But then again: where do we draw the line in consistent return types in PSL...

azjezz commented 1 year ago

I think there's a solution, we use naming to indicate what the return will be.

Psl\Collections have a method named at($k) which throws if $k is not found, and get($k) which returns T|null, we can keep this behavior and introduce a new name for return Option<T>, but, we must implement these 3 functions for all Psl\Collection, Psl\Vec, and Psl\Dict to stay consistent.

rule:

azjezz commented 1 year ago

acquire is not the best name out there, but that's what i have in mind right now, if you can think of something better, you can tell me :P

as for _typed, we should also introduce a rule for this, which would mean we deprecate Json\typed and introduce Json\decode_typed.

and it's a simple rule:

now as for acquire_typed($k): Option<T>, you can simply wrap it in a result like this:

Result\wrap(fn() => Dict\acquire_typed($arr, $k, $type))
  ->then(function($option) {

  })
  ->catch(function($type_error) {

  });
veewee commented 1 year ago

Yeah that sounds good. I don't hate acquire tbh Some possible alternatives - don't have one I really like atm:

azjezz commented 1 year ago

find is a no-go for me, Vec\find($list, $x) makes me think it's searching for an entry using $x.

try is also a no-go, this conflicts with the undocumented async convention ( see IO\ReadHandleInterface::read() vs IO\ReadHandleInterface::tryRead(), IO\WriteHandleInterface::write() vs IO\WriteHandleInterface::tryWrite(), Channel\SenderInterface::send() vs Channel\SenderInterface::trySend(), and more. )

azjezz commented 1 year ago

( there's also lock() vs tryLock(), it's more of a waiting convention, if x() might wait, there must be tryX() which doesn't wait )

veewee commented 1 year ago

Hm yeah aqcuire is one of the betters. Some synonyms, maybe you see one you likke better :)

Screenshot 2022-12-16 at 07 05 13