Code Monkey home page Code Monkey logo

Comments (28)

Pierozi avatar Pierozi commented on June 1, 2024 3

My only concern of this design is to lead us to have Option object everywhere who embed the real value.
and this Option object hide the real type of value behind where you are not able anymore to typehint.

I would prefer to go only with an Interface free to implement instead of generic Option object.

from central.

jubianchi avatar jubianchi commented on June 1, 2024 3

IMHO, Option is not something functions/methods should consume through their arguments, especially in PHP where we can't type-hint on generics (yet).

Option will avoid unexpected null usage (aka NPE in java for example). If a function/method expects a nullable argument it has to deal with it explicitly. If it does not expect a null, typehints are here to make things safe.

So, an example to show my POV:

function foo(int a) : Option/*<int>*/
{
    if ($a > 0) return Option::some($a);

    return Option::None;
}

function bar(int $a = null) : int
{
    if (null === $a) return 0;

    return $a * 2;
}

$a = rand(0, PHP_INT_MAX); // $a is an int
$b = foo($a); // $b is an Option<int>
$c = bar($a->unwrapOr(null));

Using this is, again IMHO, the only way of ensuring we get the right arguments at the right place. Without generics, if bar accepted an option, it should do something like:

function bar(Option $a) {
    $aa = $a->unwrapOr(0);

    if (is_int($a) === false) {
        throw new \InvalidArgumentException();
    }

    return $aa;
}

Here we are doing half the work of PHP, i.e checking arguments type. Not mentioning that IDE will never help us in identifying argument requirements because they will all expect an Option.

Another question : how to deal with optional arguments? Using an None option ? no way for me. This will lead to such calls everywhere:

$c = bar(Option::None);

To sum-up my POV: Options are a really good thing and it's a good idea to add them in Hoa but we should not try to force their usage everywhere and convert every null to Options. null is not a good thing, I agree, but it's here and we have to deal with it because PHP is not prepared to work as if null did not exist.

@Hywan you said

until PHP got generic (so Option will work).

If this ever happen, we will have to drop support for several PHP version to be able to use it fully.

My 2 💵 😉

from central.

Hywan avatar Hywan commented on June 1, 2024 2

I got a very concrete example today. A collection owns several products, but, new thing, a product can have no collection. So $product->collection() can return null. So calling $product->collection()->title() is now unsafe. Two solutions; first without an Option:

$title = $product->hasCollection() ? $product->collection()->title() : null;

$title can be a string or null.

Or, with an Option returned by collection():

$title = $product->collection()->map(function (Collection $collection) { return $collection->title(); });

$title is an Option.

If https://wiki.php.net/rfc/arrow_functions or another RFC of the same kind gets accepted, we could write it like this:

$title = $product->collection()->map(|Collection $collection| { return $collection->title(); });

If we omit the type-hint for Collection, we get:

$title = $product->collection()->map(|$collection| { return $collection->title });

Much better from my point of view! The null/empty case is correctly handled all the way long! No need for an extra hasCollection method; it can be replaced by $product->collection()->isSome(), the API is much simpler and safer.

from central.

mathroc avatar mathroc commented on June 1, 2024 2

@Hywan unfortunately, IDEs will probably have problem inferring option values. But is it really a big problem ?

I wouldn't mind about IDEs, it might be a bit more annoying for static analyser (eg: scrutinizer, phan). but maybe they can be taught to read generic types in docblock

from central.

Hywan avatar Hywan commented on June 1, 2024 2

So I guess we can move this RFC as ready?

from central.

Hywan avatar Hywan commented on June 1, 2024 1

https://github.com/hoaproject/Option has been released. I had to update hoa/consistency before that. Now it's time to update every library :-).

from central.

Pierozi avatar Pierozi commented on June 1, 2024

I like the idea, it's really close to immutable ValueObject concept.
In this case you have two Vo, Some and None.

I will think a bit about the implementation and give you a feedback.

from central.

Hywan avatar Hywan commented on June 1, 2024

@Pierozi Thanks for the feedback. What about the concept? Do you think it will improve safety? What about public API: Do you think users will know how to deal with Hoa\Option instead of a simple nullable value? Not to mention that public API must not return a nullable value as much as possible…

from central.

jubianchi avatar jubianchi commented on June 1, 2024

I really like everything you propose except for one thing: I don't think integrating the iterator in Option is good.

We want to deal with the presence (or absence) of valie not how we want to iterate over it. To me, constructing thz iterator, if necessary, should be delegated to the option consumer.

Moreover how would you choose which kind of iterator to produce?

from central.

Hywan avatar Hywan commented on June 1, 2024

@jubianchi Exactly. We agree on this point. This is a feature we could introduce in the future with a new RFC I guess.

from central.

jubianchi avatar jubianchi commented on June 1, 2024

@Hywan great example! 👍

With short arrow function syntax, the code would be very clear :

$title = $product->collection()->map($collection => $collection->title);

Too bad we don't have them in PHP...

But because PHP will always allow us (developers) to do weird/wrong things, I would keep the type-hint in the closure to make everything even safer:

$title = $product->collection()->map(function (Collection $collection) { return $collection->title(); });

IMHO this is the way to go. Properties are not strictly typed so anyone extending the product class can break the collection() method, making it return something inappropriate (OK, with PHP7 we should enable strict_types everywhere, but it can be disabled 😢 ). The type-hint will guarantee we actually get a Collection ensuring the call to Collection::title() is right.

from central.

vonglasow avatar vonglasow commented on June 1, 2024

LGTM 👍

from central.

Hywan avatar Hywan commented on June 1, 2024

@Pierozi The goal is to avoid having null value I think. But yes, it will hide the type of the output, until PHP got generic (so Option<MyClass> will work). What is your proposal with an interface?

from central.

mathroc avatar mathroc commented on June 1, 2024

I'm with @Pierozi on this one, I would love to have Option in php but not having generics is a major drawback:

  • IDEs won't be able to help me autocomplete
  • static analysers won't understand what object I'm getting out of the option
  • php will complain later than it could

the only way (as awful as it might be) to mitigate this I can think of would be to autogenerate classes based on the name, eg \Hoa\Option\for\Psr\Http\Message\ResponseInterface that would be the equivalent of \Hoa\Option<Psr\Http\Message\ResponseInterface>

It might help catch error earlier but I don't think this can help IDEs or static analysers (might be worst in fact 😕)

With the existing generics RFC, if \Hoa\Option happens before generics. when/if php get generics, would there be an easy path forward ? I guess it would work if we can declare a class like this:

namespace Hoa;
class Option<T = mixed> {
  public function unwrapOr(T $fallback): T {/* ... */}
}

from central.

Pierozi avatar Pierozi commented on June 1, 2024

@Hywan as quick example, i've something like this in my mind.
https://gist.github.com/Pierozi/78ccb81525ea5a29729a8518d63903f0

from central.

Hywan avatar Hywan commented on June 1, 2024

@nikic Hello :-). Do you think we have a chance to have generics inside PHP soon? Thanks!

from central.

Hywan avatar Hywan commented on June 1, 2024

@Pierozi The problem with an interface is that we have to implement all methods, or provides a trait… hmm, with a trait we will reduce the amount of bugs, that could be a nice alternative, but we still can't write:

function f(): MyObject + Option {
}

But OK, if MyObject implements an Option, then the IDE will be able to infer the methods. But this is not very clear :-/.

Thought?

from central.

Pierozi avatar Pierozi commented on June 1, 2024

Trait only work when you know the definition of object, in this case the property value, but that's depend of the object. And yes i recognize Interface are not very helpful just help to provide standardization of the Some/None in this case.

php limitation :/

from central.

Hywan avatar Hywan commented on June 1, 2024

@Pierozi You can do this:

class MyObject implements Option
{
    use OptionTrait;
}

And you have an option 😄.

from central.

Pierozi avatar Pierozi commented on June 1, 2024

Not really because your trait define arbitrary a property to use and the assertions to valid a data.
in my example the local property are named value and the assertion is true if property are not null and not
empty string.

In my point of view, trait should only be a pure function, not deal with object property.
because an interface cannot expose property, only method

from central.

Hywan avatar Hywan commented on June 1, 2024

I agree with @jubianchi. We should not use Option everytime. Also, it will force us to write code differently. For example, an optional argument can accept null, this is correct, but a mandatory argument must not receive null. Most of the time, accepting null is a bad practise. So our code will must be more robust I think.

<?php

function f(int $x): int
{
    return $x << 2;
}

f(2); // 4
f(null); // fails because null is not an integer
f(); // fails because an argument is missing

This illustrates my claim. If an argument does not accept null, it will not accept Option, this is a type error, basta (except with nullable types).

In Rust for instance, this is very rare to accept Option in argument, except for optional argument (with Into etc.). Having an Option as argument is… strange.

The power of Option is when you want to make operations on a value, like:

$product->collection()->map($c => $c->title())->map($t => $t->translate('fr_FR'));

instead of:

$translation = null;
$collection = $product->collection();

if (null !== $collection) {
    $title = $collection->title();

    if (null !== $title) {
        $translation = $title->translate('fr_FR');
    }
}

from central.

Hywan avatar Hywan commented on June 1, 2024

Now, the question remains: How to be compatible with IDE? I don't use an IDE, so I can't answer this answer :-(.

from central.

jubianchi avatar jubianchi commented on June 1, 2024

@Hywan unfortunately, IDEs will probably have problem inferring option values. But is it really a big problem ?

Today, with PHP and IDE, we can't be sure and get hints on collections for example: a function expects a collection (let's say a SplObjectStorage) we can't be sure of the items' type it expects and the one it gets.

The problem exists and we can't deal with it today... no generics support in the language and no generics support in PHPDoc annotation.

I just tested with PHPStorm (2016.2):

<?php

class Option {}


/**
 * @return Option<int>
 */
function foo(Option $a) : Option
{
    return $a;
}

$b = foo(new Option);

PHPStorm tells me $b is an Option, that's all. I does not read the generic part of the @return annotation.

IMHO, IDE are a "fake" problem: we can do everything we want to make the code self-documented and provide IDE with what they need, developers will always have to read the library source code at some point to know what they should provide or what they should expect.

from central.

Hywan avatar Hywan commented on June 1, 2024

Hello fellow @hoaproject/hoackers!

I have created the new library Hoa\Option, https://github.com/hoaproject/Option. Please, review it before releasing the 1.0 version.

If no feedback before the 21st August 2017, I will release the 1.0 version.

Take care of the documentation, the PHP 7.1 requirement, the build matrix on Travis etc. please.

from central.

mathroc avatar mathroc commented on June 1, 2024

nice ☺

just a one things after reading the README

is there a difference between $a->mapOr($map, $or) and $a->map($map)->or($or) ? same for all *Or*() methods, and if there’s no differences, are they really useful ?

from central.

mathroc avatar mathroc commented on June 1, 2024

note: I half expected something using along the line of Finite-State Machine as a Type System illustrated with a store product with an Option interface and 2 classes Some & None but then I don’t how to prevent someone else to implement the Option interface

from central.

Hywan avatar Hywan commented on June 1, 2024

You're correct, mapOr(…) is equivalent to map(…)->or(…) except that we have 2 calls and 1 more allocation with map(…)->or(…). So mapOr(…) is a convenient shortcut. However, wrapOr(…) is not similar to wrap(…)->or(…) because wrap does not return an Option.

I propose to keep the mapOr method, thought?

from central.

Hywan avatar Hywan commented on June 1, 2024

About the article you mentionned, this is not applicable here because an option is a monad, all the methods return a new option, there is no particular state (with a PHP implementation).

from central.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.