[PSR-13] "With-er" methods

422 views
Skip to first unread message

Larry Garfield

unread,
Jul 7, 2016, 8:22:12 PM7/7/16
to php...@googlegroups.com
One last question on PSR-13 before I turn it over to Matthew for Review.

Currently, PSR-13 includes only getter methods. As noted in the
metadoc, this is by design as the interfaces could be implemented by
something other than a dumb value object, in which case it is
nonsensical to try and set values. It could also be implemented by an
immutable object, such as a PSR-7 Response, in which case setters would
be incompatible with the Response object's definition.

However, I could also see cases where a standard way to SET the value
for a Link, or to add a Link to a collection. Most notably, a Response
object, where you may want to add links to it in a standard way. Of
course, in such cases we'd have to use a with*() method, a la PSR-7 to
ensure that it's compatible with other immutable value objects.

To that end, I would propose adding one or two additional interfaces
that extend the existing interfaces and add with*() methods. For lack
of a better term, since they're not really mutable, I will call these
"Wither" methods. (A better name is very, very welcome.)

For collections, it would likely contain only a single method,
withLink(LinkInterface), which adds a link object to the collection and
returns the collection. That would cover the Response case.

For links themselves, I expect it would contain withRel(), withHref(),
withAttribute(), withoutAttribute(), and withTemplated().

As before, I've some proof of concept code from a while back here:

https://github.com/Crell/HtmlModel/tree/master/src/Link

Therefore:

1) Add a WitherableLinkInterface extends LinkInterface
2) Add a WitherableLinkCollectionInterface extends LinkCollectionInterface
3) Both
4) Neither

My inclination at the moment is option 2; I can definitely see the use
for that one, and it actually is, I think, key to the common use cases
we've identified (such as transferring links from one value object to
another). The link object itself, eh, I can take it or leave it. I
will probably go that route unless there are any major objections, and
assuming we can come up with a better name than "Witherable". :-)

Thoughts?

--Larry Garfield

Woody Gilk

unread,
Jul 8, 2016, 10:20:46 AM7/8/16
to PHP Framework Interoperability Group
On Thu, Jul 7, 2016 at 7:22 PM, Larry Garfield <la...@garfieldtech.com> wrote:
> To that end, I would propose adding one or two additional interfaces that
> extend the existing interfaces and add with*() methods. For lack of a
> better term, since they're not really mutable, I will call these "Wither"
> methods. (A better name is very, very welcome.)


What about calling them "copyable"? Don't completely love the name
either, but "CopyOnWriteAble" seemed a bit verbose.
--
Woody Gilk
http://about.me/shadowhand

Larry Garfield

unread,
Jul 12, 2016, 4:19:00 PM7/12/16
to php...@googlegroups.com
Eh. You can copy any object, though, with an external clone() call. So
really, all objects are "copyable", aren't they?

--Larry Garfield

Ciaran McNulty

unread,
Jul 14, 2016, 10:27:02 AM7/14/16
to PHP Framework Interoperability Group
On Tuesday, 12 July 2016 21:19:00 UTC+1, Larry Garfield wrote:
Eh.  You can copy any object, though, with an external clone() call.  So
really, all objects are "copyable", aren't they?

--Larry Garfield

You can certainly prevent an object being cloned, unless you mean a more complex case?

final class A
{
    private function __clone() {}
}

$a = new A;
$b = clone $a; // error - Call to private A::__clone() from ...

-Ciaran

Larry Garfield

unread,
Jul 14, 2016, 4:16:31 PM7/14/16
to php...@googlegroups.com
Well yes, I mean that by default any object is clonable, therefore copy-able, therefore

interface CopyableLinkCollectionInterface extends LinkCollectionInterface {

  public function withLink() : self;

  public function withoutLink() : self;

}

is a bad name for that interface.  That's all we need to name right now, is that interface. :-)  Copyable is too generic, Withable sounds too weird, they're not mutators to Mutable*Interface is wrong.  Other suggestions?

--Larry Garfield

Jason Walker

unread,
Jul 14, 2016, 5:49:43 PM7/14/16
to PHP Framework Interoperability Group
How do the prefixes "Configurable" or "Amendable" sound?

E.g.

ConfigurableLinkInterface
ConfigurableLinkCollectionInterface

...or...

AmendableLinkInterface
AmendableLinkCollectionInterface

Daniel Hunsaker

unread,
Jul 26, 2016, 8:32:20 PM7/26/16
to PHP Framework Interoperability Group
One of the biggest difficulties here is that most of the synonyms for "can be changed" already have meanings in programming contexts...  Meanings we'd want to avoid implying, here.  That means many otherwise-great options risk too much confusion to be useful. Even Fractal's choice to use 'include' instead of 'with' isn't necessarily all that helpful here. Even so, not proposing options in a brainstorm is how we get deadlock, so here you go:
  • Appendable
  • Combinable
  • Revisable
  • Alterable
  • Assignable
  • Updatable
  • Variable
  • Extensible
  • Expandable
  • Embracing
  • Composable
  • Evolving (or Evolvable)
  • Adoptable (or Adoptive)
  • Insertable
  • Inductable
  • Annexible
  • Coupled
My personal favorite, though, is to actually use a suffix instead:

LinkWithInterface extends LinkInterface 
LinkCollectionWithInterface extends LinkCollectionInterface

This does have the side effect of diminishing the focus on the key difference between the interfaces, though, by "burying" it in the interface name.  So it may not be ideal.

Just some thoughts (provided mostly by burying my head in an online thesaurus).

- Daniel Hunsaker 

Woody Gilk

unread,
Jul 27, 2016, 10:00:29 AM7/27/16
to PHP Framework Interoperability Group
Daniel, that's a great list for thought. I particularly like Evolvable.

Maybe the term idempotent fits in here somewhere as well? Calling with* methods do not change the underlying object, but return a different instance?

I wish there was a well-defined term for "Copy on Write" because that's the simplest way I've found to describe how with* methods work.

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/239b7c02-9661-462b-af5f-7da233ce884f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Théo FIDRY

unread,
Jul 29, 2016, 4:02:01 PM7/29/16
to PHP Framework Interoperability Group
Although it's not proper english, "Wither" has the advantage to be 1. simple (with -> wither) and in line with "getter" and "setter". There may be a better word to describe those non-static factories, but "wither" is good enough IMO.

Théo FIDRY

Matthew Weier O'Phinney

unread,
Aug 1, 2016, 10:31:38 AM8/1/16
to php...@googlegroups.com
On Fri, Jul 29, 2016 at 3:02 PM, Théo FIDRY <theo....@gmail.com> wrote:
> Although it's not proper english, "Wither" has the advantage to be 1. simple
> (with -> wither) and in line with "getter" and "setter". There may be a
> better word to describe those non-static factories, but "wither" is good
> enough IMO.

As a native English speaker, "wither" has another meaning entirely: to
shrivel and die.

I'm personally +1 for Evolvable:

- EvolvableLinkInterface
- EvolvableLinkCollectionInterface
> https://groups.google.com/d/msgid/php-fig/8e9a6492-ddff-40c7-977b-da7666bea139%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Larry Garfield

unread,
Aug 1, 2016, 3:17:36 PM8/1/16
to php...@googlegroups.com
On 08/01/2016 09:31 AM, Matthew Weier O'Phinney wrote:
> On Fri, Jul 29, 2016 at 3:02 PM, Théo FIDRY <theo....@gmail.com> wrote:
>> Although it's not proper english, "Wither" has the advantage to be 1. simple
>> (with -> wither) and in line with "getter" and "setter". There may be a
>> better word to describe those non-static factories, but "wither" is good
>> enough IMO.
> As a native English speaker, "wither" has another meaning entirely: to
> shrivel and die.
>
> I'm personally +1 for Evolvable:
>
> - EvolvableLinkInterface
> - EvolvableLinkCollectionInterface

Evolvable works for me. PR is here:

https://github.com/php-fig/fig-standards/pull/788

Matthew, please merge in a day or three if no one else comments. After
that, I think we're ready for Review.

--Larry Garfield

Alexandru Pătrănescu

unread,
Aug 1, 2016, 6:02:06 PM8/1/16
to php...@googlegroups.com
Hi all,

Just like along with get is is also a getter, the same way with is also a setter. If you really want to distinguish it, it is a fluent setter.

Using with methods has nothing to do with the object being immutable and does not enforce that the method will return a new instance.
It's a common practice to use them for builder pattern for example: 
$car = (new CarBuilder())->withNumberOfWeels(4)->withColor(CarColor::RED())->withFuelType(FuelType::DIESEL())->build();
Probably the CardBuilder with* methods with not return a new instance. But if the implementer decides, it could also make the CarBuilder immutable and always return a fresh instance.

Your keep linking the with methods (from the interface) with the immutability property (of the implementation) and I believe it will not bring any benefit on the long run; people might confuse them.

Related to interface, I think it is ok-ish, although I don't really believe in interface that contains setters. It could be fine if we think it is also a creator/builder/factory inside that class that can create more objects and we want to standardize the way it works.
If you decide to go with it, what I think it would be good is a set of interface tests so that an implementation could easily run them. We could test immutability there ;).

We could use another interface for changing the object (just to separate the concerns) that will have methods like LinkChanger::changeHref(Link $link, $href) : Link.
But that will not enforce immutability also; you can only write tests to check that the initial object didn't change.

Regards,
Alex


--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages