Welcome! Log In Create A New Profile

Advanced

[PHP-DEV] Type variants

Posted by Michael Vostrikov 
Michael Vostrikov
[PHP-DEV] Type variants
March 11, 2017 07:40AM
Hello. I have an idea which seems rather useful. I would like to know your
opinion,

Let's say we have class Rectangle and need to have class Square which will
be used in some operations. We don't need any rectangle, this must be only
square.
What if we could describe a type which is the same as another type but have
some restrictions for properties?

Something like this:

class Rectangle
{
private $x;
private $y;
private $width;
private $height;

public function __construct($x, $y, $width, $height)
{
$this->x = $x;
$this->y = $y;
$this->width = $width;
$this->height = $height;
}
}

class Square variant of Rectangle
{
public function __match()
{
if ($this->width != $this->height) {
return ['width' => 'Width and height have to be the same'];
}

return true;
}
}

function drawSquare(Square $square)
{
// ...
}

$rectangle = new Rectagle(0, 0, 10, 10);
drawSquare($rectangle);

When drawSquare() is called, the check 'instanceof' is performed. It calls
magic method __match().
If __match() does not return true, it throws an exception with the data
returned:
'Order does not match OrderForCheckout. Reason: ...'.


Technically, we don't have method __match() in $rectangle object. So it can
be static, or a proxy object can be created here.

The second variant can be extended.
We may not to inherit implementation of methods, and describe another
interface instead, for example new object can be read only.

class Square variant of Rectangle
{
public function ___match()
{
// ...
}

public function getWidth()
{
return parent::getWidth();
}
}

With some changes in syntax it can be defined in this way:

class Square variant of Rectangle
{
...

getWidth: base::getWidth;
}


This is like inheritance, but semantically differs a little.
Inheritance has vertical direction, type variants have horisontal one.
Also type variants have an access for all methods and properties of base
class, even for private.


Another example. Let's say we have an order checkout process which is
splitted into 3 steps - cart for products, date page, delivery address page.
This is not an input validation, this is a validation in business logic.

class Order
{
public $products;
public $date;
public $address;
}

class OrderForCheckout variant of Order
{
public function __match()
{
$errors = [];
if (empty($this->products)) {
$errors['products'] = 'Product list is empty';
}
if ($this->date === null) {
$errors['date'] = 'Date is not selected';
}
if (empty($this->products)) {
$errors['address'] = 'Address is not selected';
}

return (empty($errors) ? true : $errors);
}
}

public function checkout(OrderForCheckout $order)
{
...
}

$order = findCurrentOrder();
checkout($order); // if $order does not match requirements, the exception
will be thrown
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 11, 2017 05:30PM
> 'Order does not match OrderForCheckout. Reason: ...'.

Sorry, this is text for second example) I missed this moment. But I think
the idea is clear.


For manual call of __match() type casting can be used:
$orderForCheckout = (OrderForCheckout)$order;


Also this feature can be used for checking enum values or intervals.

class Value
{
public $value;

public function __construct($value)
{
$this->value = $value;
}
}

class State variant of Value
{
const ACTIVE = 1;
const INACTIVE = 2;

public function __match()
{
return in_array($this->value, [self::ACTIVE, self::INACTIVE]);
}
}

function setState(State $s)
{
...
}

setState(new State(3));

In constructions like "new State($value)" __match() can be called after
__construct().


If to add a possibility to use data types, class Value will not be needed:

class State variant of integer
{
...
public function __match()
{
return in_array($this, [self::ACTIVE, self::INACTIVE]);
}
}

setState(3);
Michał Brzuchalski
Re: [PHP-DEV] Type variants
March 12, 2017 06:30AM
2017-03-11 17:24 GMT+01:00 Michael Vostrikov <[email protected]>:

> > 'Order does not match OrderForCheckout. Reason: ...'.
>
> Sorry, this is text for second example) I missed this moment. But I think
> the idea is clear.
>
>
> For manual call of __match() type casting can be used:
> $orderForCheckout = (OrderForCheckout)$order;
>
>
> Also this feature can be used for checking enum values or intervals.
>
> class Value
> {
> public $value;
>
> public function __construct($value)
> {
> $this->value = $value;
> }
> }
>
> class State variant of Value
> {
> const ACTIVE = 1;
> const INACTIVE = 2;
>
> public function __match()
> {
> return in_array($this->value, [self::ACTIVE, self::INACTIVE]);
> }
> }
>
> function setState(State $s)
> {
> ...
> }
>
> setState(new State(3));
>
> In constructions like "new State($value)" __match() can be called after
> __construct().
>
>
> If to add a possibility to use data types, class Value will not be needed:
>
> class State variant of integer
> {
> ...
> public function __match()
> {
> return in_array($this, [self::ACTIVE, self::INACTIVE]);
> }
> }
>
> setState(3);
>

IMHO the real life implementations always differ, in another case, they
would be the same.
Example with Rectangle and Square IMO is an example of bad naming in this
case.
I rather want to call it Quadrangle and have one implementation or event do
the simplest inheritation.
But I may be wrong.

--
regards / pozdrawiam,
--
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
Sherif Ramadan
Re: [PHP-DEV] Type variants
March 12, 2017 07:10AM
PHP already has horizontal inheritance. They're called traits.

How is this an improvement in anyway?

On Sat, Mar 11, 2017 at 1:36 AM, Michael Vostrikov <
[email protected]> wrote:

> Hello. I have an idea which seems rather useful. I would like to know your
> opinion,
>
> Let's say we have class Rectangle and need to have class Square which will
> be used in some operations. We don't need any rectangle, this must be only
> square.
> What if we could describe a type which is the same as another type but have
> some restrictions for properties?
>
> Something like this:
>
> class Rectangle
> {
> private $x;
> private $y;
> private $width;
> private $height;
>
> public function __construct($x, $y, $width, $height)
> {
> $this->x = $x;
> $this->y = $y;
> $this->width = $width;
> $this->height = $height;
> }
> }
>
> class Square variant of Rectangle
> {
> public function __match()
> {
> if ($this->width != $this->height) {
> return ['width' => 'Width and height have to be the same'];
> }
>
> return true;
> }
> }
>
> function drawSquare(Square $square)
> {
> // ...
> }
>
> $rectangle = new Rectagle(0, 0, 10, 10);
> drawSquare($rectangle);
>
> When drawSquare() is called, the check 'instanceof' is performed. It calls
> magic method __match().
> If __match() does not return true, it throws an exception with the data
> returned:
> 'Order does not match OrderForCheckout. Reason: ...'.
>
>
> Technically, we don't have method __match() in $rectangle object. So it can
> be static, or a proxy object can be created here.
>
> The second variant can be extended.
> We may not to inherit implementation of methods, and describe another
> interface instead, for example new object can be read only.
>
> class Square variant of Rectangle
> {
> public function ___match()
> {
> // ...
> }
>
> public function getWidth()
> {
> return parent::getWidth();
> }
> }
>
> With some changes in syntax it can be defined in this way:
>
> class Square variant of Rectangle
> {
> ...
>
> getWidth: base::getWidth;
> }
>
>
> This is like inheritance, but semantically differs a little.
> Inheritance has vertical direction, type variants have horisontal one.
> Also type variants have an access for all methods and properties of base
> class, even for private.
>
>
> Another example. Let's say we have an order checkout process which is
> splitted into 3 steps - cart for products, date page, delivery address
> page.
> This is not an input validation, this is a validation in business logic.
>
> class Order
> {
> public $products;
> public $date;
> public $address;
> }
>
> class OrderForCheckout variant of Order
> {
> public function __match()
> {
> $errors = [];
> if (empty($this->products)) {
> $errors['products'] = 'Product list is empty';
> }
> if ($this->date === null) {
> $errors['date'] = 'Date is not selected';
> }
> if (empty($this->products)) {
> $errors['address'] = 'Address is not selected';
> }
>
> return (empty($errors) ? true : $errors);
> }
> }
>
> public function checkout(OrderForCheckout $order)
> {
> ...
> }
>
> $order = findCurrentOrder();
> checkout($order); // if $order does not match requirements, the exception
> will be thrown
>
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 07:40AM
> Example with Rectangle and Square IMO is an example of bad naming in this
case.

I used this example because this is known problem of inheritance. Type
variants solve this problem. Square is a particular case (variant) of
Rectangle.

> PHP already has horizontal inheritance. They're called traits. How is
this an improvement in anyway?

Trait is just reusable implementation. I suggest type matching. This is
extension of type hinting. It can be used in all cases where we need to
check if an object matches some criterias before continue operation. It is
a kind of defensive programming and a replacement for many 'if-throw'
constructions.
Sherif Ramadan
Re: [PHP-DEV] Type variants
March 12, 2017 07:50AM
Yea, but how's that an improvement over using an interface?

On Sun, Mar 12, 2017 at 1:38 AM, Michael Vostrikov <
[email protected]> wrote:

> > Example with Rectangle and Square IMO is an example of bad naming in this
> case.
>
> I used this example because this is known problem of inheritance. Type
> variants solve this problem. Square is a particular case (variant) of
> Rectangle.
>
> > PHP already has horizontal inheritance. They're called traits. How is
> this an improvement in anyway?
>
> Trait is just reusable implementation. I suggest type matching. This is
> extension of type hinting. It can be used in all cases where we need to
> check if an object matches some criterias before continue operation. It is
> a kind of defensive programming and a replacement for many 'if-throw'
> constructions.
>
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 08:00AM
2017-03-12 11:41 GMT+05:00 Sherif Ramadan <[email protected]>:

> Yea, but how's that an improvement over using an interface?
>
>
How can I check if an order is ready for checkout with interface? The
difference is in property values, not in presence of methods.
Sherif Ramadan
Re: [PHP-DEV] Type variants
March 12, 2017 08:10AM
You could have an abstract classes implement the interface and extend from
the abstract classes.

On Sun, Mar 12, 2017 at 1:57 AM, Michael Vostrikov <
[email protected]> wrote:

> 2017-03-12 11:41 GMT+05:00 Sherif Ramadan <[email protected]>:
>
> > Yea, but how's that an improvement over using an interface?
> >
> >
> How can I check if an order is ready for checkout with interface? The
> difference is in property values, not in presence of methods.
>
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 08:20AM
2017-03-12 12:03 GMT+05:00 Sherif Ramadan <[email protected]>:

> You could have an abstract classes implement the interface and extend from
> the abstract classes.
>
>
Ok, could you give an example, how to check described requirements with
interface?
Sherif Ramadan
Re: [PHP-DEV] Type variants
March 12, 2017 08:30AM
Which requirements are those exactly?


On Sun, Mar 12, 2017 at 3:15 AM, Michael Vostrikov <
[email protected]> wrote:

> 2017-03-12 12:03 GMT+05:00 Sherif Ramadan <[email protected]>:
>
>> You could have an abstract classes implement the interface and extend
>> from the abstract classes.
>>
>>
> Ok, could you give an example, how to check described requirements with
> interface?
>
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 08:50AM
2017-03-12 12:19 GMT+05:00 Sherif Ramadan <[email protected]>:

> Which requirements are those exactly?
>

An order should have count of products > 0 and date and address filled
before checkout procedure.
Sherif Ramadan
Re: [PHP-DEV] Type variants
March 12, 2017 09:10AM
I'm not sure what that has to do with inheritance exactly or how it
pertains to this discussion. This is an implementation detail.

On Sun, Mar 12, 2017 at 3:47 AM, Michael Vostrikov <
[email protected]> wrote:

> 2017-03-12 12:19 GMT+05:00 Sherif Ramadan <[email protected]>:
>
> > Which requirements are those exactly?
> >
>
> An order should have count of products > 0 and date and address filled
> before checkout procedure.
>
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 09:20AM
2017-03-12 13:03 GMT+05:00 Sherif Ramadan <[email protected]>:

how it pertains to this discussion
>

This is example of type matching from my first message.

I'm not sure what that has to do with inheritance
>

Yes, this is not related with inheritance. But order can be ready for
checkout or can not. This is a variant of valid object state. If we could
have a tool to describe that and check later, it would be useful.
Sherif Ramadan
Re: [PHP-DEV] Type variants
March 12, 2017 10:00AM
If the problem you're trying to solve pertains to object state that I have
no idea how this proposal hopes to achieve that. You can readily control
object state in PHP without the need for declarative types (e.g. magic
getters/setters). Not seeing how this proposal improves or even achieves
such a thing. I think you're trying desperately to find a problem that is
fitting of the proposal whereas all real-world problems that exist under
this domain are already solved problems.

On Sun, Mar 12, 2017 at 4:17 AM, Michael Vostrikov <
[email protected]> wrote:

> 2017-03-12 13:03 GMT+05:00 Sherif Ramadan <[email protected]>:
>
> how it pertains to this discussion
> >
>
> This is example of type matching from my first message.
>
> I'm not sure what that has to do with inheritance
> >
>
> Yes, this is not related with inheritance. But order can be ready for
> checkout or can not. This is a variant of valid object state. If we could
> have a tool to describe that and check later, it would be useful.
>
Lester Caine
Re: [PHP-DEV] Type variants
March 12, 2017 10:20AM
On 11/03/17 06:36, Michael Vostrikov wrote:
> $rectangle = new Rectangle(0, 0, 10, 10);
> drawSquare($rectangle);
>
> When drawSquare() is called, the check 'instanceof' is performed. It calls
> magic method __match().
> If __match() does not return true, it throws an exception with the data
> returned:

My problem here is with the reason for needing a different class for
'Square' when $rectangle->is_square() is a simple additional check on a
single Rectangle class. drawSquare() seems redundant when
$rectangle->draw() does the same job ... a lot of duplicate code for
little gain? My problem I think is 'instanceof' is being used
incorrectly here.

> 'Order does not match OrderForCheckout. Reason: ...'.

The class is 'Order' which in my book will be a variable list of
'LineItem' and each line item will have a status such as is_instock().
The Order status of is_shipable() flags an order that is ready for
shipment which will produce an answer of yes, partial or no.

Just as you don't need to change Rectangle->Square just because you want
to draw a square with a set of numbers which started as a Rectangle, you
don't want to change the class from Order to OrderForCheckout. The base
order simple has a set of constraints which must be met before is_ready
can apply and is_billable will flag if you only charge for a shipment,
or take a full payment with order. LineItem has a check on 'backorder'
to validate if it's allowed to add items which are out of stock.

While I think I can see the logic behind describing these as different
types of object I think it is the same mistake as strictly enforcing
'int' when the raw data you have is a string of numbers. And just
because you know you have a number for the quantity to buy you still
need to check that against the stock level and handle it differently if
there is not sufficient stock. Trying to create 'type's for all the
variants of the object is just wrong? int_instock, int_minorder,
int_backorder, int_special_production and so on as the types of LineItem
so 'instanceof' will work for you?

--
Lester Caine - G8HFL
-----------------------------
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 10:40AM
2017-03-12 13:58 GMT+05:00 Sherif Ramadan <[email protected]>:

> I think you're trying desperately to find a problem that is fitting of
the proposal

Checks in business logic are popular task.

> If the problem you're trying to solve pertains to object state that I
have no idea how this proposal hopes to achieve that. You can readily
control object state in PHP without the need for declarative types (e.g.
magic getters/setters)

I described in first message the way how the proposal can help with this.
There is no magic getters/setters there.

> Not seeing how this proposal improves or even achieves such a thing.

Now we need to write in business logic the following:

function checkout(Order $order)
{
if (count($order->products) > 0) {
throw new SomeException1();
}
if ($order->date === null) {
throw new SomeException2();
}
if ($order->address === null) {
throw new SomeException3();
}

// checkout steps
...
someActionWithOrderForCheckout($order);
...
}

function someActionWithOrderForCheckout(Order $order)
{
if (count($order->products) > 0) {
...
}
if ()
...
}


Of course, we can move all checks to some function like
'ensureOrderIsReadyForCheckout()' and call it everywhere manually.
But this is the same as call is_integer() manually instead of type hinting.
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 10:40AM
2017-03-12 14:14 GMT+05:00 Lester Caine <[email protected]>:

> My problem here is with the reason for needing a different class for
'Square' when $rectangle->is_square() is a simple additional check on a
single Rectangle class.

Yes. And we have to call it in all operations with Square manually, and
throw exceptions/return errors manually.

> drawSquare() seems redundant when $rectangle->draw() does the same job

This is just example of external function with type hinting. And I'm not
sure that models should know about device contexts, canvases, pixels and
other details of presentation layer.

> Trying to create 'type's for all the variants of the object is just
wrong? int_instock, int_minorder, int_backorder, int_special_production and
so on as the types of LineItem so 'instanceof' will work for you?

I don't need to create a separate type for every characteristic. I need to
create a type for some important operations, which will contain all
required restictions of object state and which I could just write in all
functions that work with this state.
Fleshgrinder
Re: [PHP-DEV] Type variants
March 12, 2017 11:00AM
On 3/12/2017 10:36 AM, Michael Vostrikov wrote:
> Now we need to write in business logic the following:
>
> function checkout(Order $order)
> {
> if (count($order->products) > 0) {
> throw new SomeException1();
> }
> if ($order->date === null) {
> throw new SomeException2();
> }
> if ($order->address === null) {
> throw new SomeException3();
> }
>
> // checkout steps
> ...
> someActionWithOrderForCheckout($order);
> ...
> }
>
> function someActionWithOrderForCheckout(Order $order)
> {
> if (count($order->products) > 0) {
> ...
> }
> if ()
> ...
> }
>
>
> Of course, we can move all checks to some function like
> 'ensureOrderIsReadyForCheckout()' and call it everywhere manually.
> But this is the same as call is_integer() manually instead of type hinting.
>

The problem you are facing is that you are dealing with an anemic domain
object that does not enforce its own invariants. Properly applying OOD
principles would remedy all your problems. However, you do not require
new features to do that.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 11:40AM
2017-03-12 14:58 GMT+05:00 Fleshgrinder <[email protected]>:

> The problem you are facing is that you are dealing with an anemic domain
> object that does not enforce its own invariants.
>

Incomlplete order with date and address not set yet is a valid state of
order.
Also, there are many cases when logic which includes many objects is placed
in a service and not in any of that objects.

> However, you do not require new features to do that.

I don't tell that we cannot make that with current features. I suggest a
way to do that more easy. This is like type hinting. We can check types
manually by calling functions like is_integer() or get_class(), but we
don't have a question why we need to have type hinting in language.
Yasuo Ohgaki
Re: [PHP-DEV] Type variants
March 12, 2017 11:40AM
Hi Michael,

On Sat, Mar 11, 2017 at 3:36 PM, Michael Vostrikov <
[email protected]> wrote:

>
> class Square variant of Rectangle
> {
> public function __match()
> {
> if ($this->width != $this->height) {
> return ['width' => 'Width and height have to be the same'];
> }
>
> return true;
> }
> }
>

DbC allows this kind of validation at development time.
I suppose you would like to check requirement at runtime always.
It would be nice to have feature, but I think

something like __requrie()

is better name for the method.
IMO, C# like getter/setter is better though.

http://stackoverflow.com/questions/11159438/looking-for-a-short-simple-example-of-getters-setters-in-c-sharp

Regards,

--
Yasuo Ohgaki
yohgaki@ohgaki.net
Fleshgrinder
Re: [PHP-DEV] Type variants
March 12, 2017 11:40AM
On 3/12/2017 11:29 AM, Michael Vostrikov wrote:
> 2017-03-12 14:58 GMT+05:00 Fleshgrinder <[email protected]>:
>> The problem you are facing is that you are dealing with an anemic domain
>> object that does not enforce its own invariants.
>>
>
> Incomlplete order with date and address not set yet is a valid state of
> order.
> Also, there are many cases when logic which includes many objects is placed
> in a service and not in any of that objects.

Sure, but you should still not have an anemic domain. Any object needs
to ensure its own invariants, that's nothing another service should do.
You are clearly dealing with two kinds of orders, hence, create two
kinds of orders. `IncompleteOrder` is the one without date, address, and
probably even products. You directly named it as such. Then you have
`ProcessableOrder` where this is impossible. **BAM** all problems solved.

On 3/12/2017 11:29 AM, Michael Vostrikov wrote:
> 2017-03-12 14:58 GMT+05:00 Fleshgrinder <[email protected]>:
>> However, you do not require new features to do that.
>
> I don't tell that we cannot make that with current features. I suggest a
> way to do that more easy. This is like type hinting. We can check types
> manually by calling functions like is_integer() or get_class(), but we
> don't have a question why we need to have type hinting in language.

The problem is that your proposal is meant to solve problems that are
already solved in a way that is not really understood by anyone so far.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Fleshgrinder
Re: [PHP-DEV] Type variants
March 12, 2017 11:50AM
On 3/12/2017 11:33 AM, Yasuo Ohgaki wrote:
> DbC allows this kind of validation at development time.
> I suppose you would like to check requirement at runtime always.
> It would be nice to have feature, but I think
>
> something like __requrie()
>
> is better name for the method.
> IMO, C# like getter/setter is better though.
>
> http://stackoverflow.com/questions/11159438/looking-for-a-short-simple-example-of-getters-setters-in-c-sharp
>

Hey Yasuo! :)

Design by Contract is a nice thing, and you know that I would love to
see it as part of the language. However, it is not really the solution
to the problem that is being described here, since it is a valid state
for an order to be empty. The stated Square-Rectangle example is a
different beast, and there are many solutions to it. I probably would
argue that Rectangle needs to extend Square and not the other way.
Square has an extended functionality compared to Rectangle while being
fully compatible.

DbC would still be nice and would allow us to add real invariant, pre-,
and post-conditions. I, as you might remember, would not go for a magic
method but rather an extended block, like we see it for if-else or
try-catch:

class C {}
invariant {} // one assert per line

function f() {}
requires {} // pre-conditions
ensures {} // post-conditions

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 03:00PM
2017-03-12 15:33 GMT+05:00 Yasuo Ohgaki <[email protected]>:
> DbC allows this kind of validation at development time.
> I suppose you would like to check requirement at runtime always.

Yes, DbC from here https://wiki.php.net/rfc/dbc2 describes similar things.
This is good idea, but I tell more about checks which cannot be removed
from code. Types which meet some requirements looks more closer to business
logic terms than constructions like if-throw or
require($order->isReadyForSomething()).


2017-03-12 15:35 GMT+05:00 Fleshgrinder <[email protected]>:
> `IncompleteOrder` is the one without date, address, and
> probably even products. You directly named it as such. Then you have
> `ProcessableOrder` where this is impossible

Yes, this is Order and OrderForCheckout in my example. But they should not
be descendants of base class or each other. Because allowed class states
are not descendants of that class.

> **BAM** all problems solved.

Yeah, now we have:
base Order
IncompleteOrder extends Order
ProcessableOrder extends Order
PaidOrder extends Order // or ProcessableOrder?

and later could get:
WholesaleOrder extends Order

with a question how to extend classes in new branch.


Also the problem is how to use this tree in relations.

There is class OrderItem with $order property.
There is class Customer with $orders property.
What classes should have these properties? Every time different?

This is a part of another problem that we need to decide what exact class
should be created here or there before calling a function which uses it.


With type variants (hm, or invariants) it could be:
Order
ProcessableOrder variant of Order
PaidOrder variant of Order
WholesaleOrder variant of Order

And everywhere we can create and use objects with class Order, and only in
some functions they will be considered as processable or not.
Fleshgrinder
Re: [PHP-DEV] Type variants
March 12, 2017 03:00PM
On 3/12/2017 2:49 PM, Michael Vostrikov wrote:
> 2017-03-12 15:35 GMT+05:00 Fleshgrinder <[email protected]>:
>> `IncompleteOrder` is the one without date, address, and
>> probably even products. You directly named it as such. Then you have
>> `ProcessableOrder` where this is impossible
>
> Yes, this is Order and OrderForCheckout in my example. But they should not
> be descendants of base class or each other. Because allowed class states
> are not descendants of that class.
>
>> **BAM** all problems solved.
>
> Yeah, now we have:
> base Order
> IncompleteOrder extends Order
> ProcessableOrder extends Order
> PaidOrder extends Order // or ProcessableOrder?
>
> and later could get:
> WholesaleOrder extends Order
>
> with a question how to extend classes in new branch.
>
>
> Also the problem is how to use this tree in relations.
>
> There is class OrderItem with $order property.
> There is class Customer with $orders property.
> What classes should have these properties? Every time different?
>
> This is a part of another problem that we need to decide what exact class
> should be created here or there before calling a function which uses it.
>
>
> With type variants (hm, or invariants) it could be:
> Order
> ProcessableOrder variant of Order
> PaidOrder variant of Order
> WholesaleOrder variant of Order
>
> And everywhere we can create and use objects with class Order, and only in
> some functions they will be considered as processable or not.
>

Post this on Stackoverflow and I'll give you some answers and possible
approaches. ;) You are clearly struggling with architecture and design,
but you are definitely not missing language constructs here.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 12, 2017 06:20PM
2017-03-12 18:54 GMT+05:00 Fleshgrinder <[email protected]>:

>
> Post this on Stackoverflow and I'll give you some answers and possible
> approaches. ;) You are clearly struggling with architecture and design,
> but you are definitely not missing language constructs here.
>
> --
> Richard "Fleshgrinder" Fussenegger
>

No, thanks) I don't have real problem. I know some problems with usual
inheritance and try to suggest the tool to solve them. Problems which are
mostly kinds of Rectangle-Square problem, and where is some restrictions in
derived types.
Fleshgrinder
Re: [PHP-DEV] Type variants
March 12, 2017 07:10PM
On 3/12/2017 6:16 PM, Michael Vostrikov wrote:
> No, thanks) I don't have real problem. I know some problems with usual
> inheritance and try to suggest the tool to solve them. Problems which are
> mostly kinds of Rectangle-Square problem, and where is some restrictions in
> derived types.
>

As I said already, there is no problem if you just change the direction
of the inheritance.

class Square {
private $x;
private $y;
private $w;

public function __construct(int $x, int $y, int $w) {
$this->x = $x;
$this->y = $y;
$this->w = $w;
}

public function draw(Canvas $canvas): void { }
}

class Rectangle extends Square {
private $h;

public function __construct(int $x, int $y, int $w, int $h) {
parent::__construct($x, $y, $w);
$this->height = $h;
}

public function draw(Canvas $canvas): void { }
}

If you want to ensure that you always get a Square if width and height
match, no problem either.

class Square {
private $x;
private $y;
private $w;
private $h;

final protected function __construct(
int $x, int $y, int $w, int $h
) {
$this->x = $x;
$this->y = $y;
$this->w = $w;
$this->h = $h;
}

public static function new(int $x, int $y, int $w): self {
return new self($x, $y, $w, $w);
}

public function draw(Canvas $canvas): void { }
}

class Rectangle extends Square {
public static function new(
int $x, int $y, int $w, ?int $h = null
): parent {
if ($h === null || $w === $h) {
return new parent($x, $y, $w, $w);
}
return new self($x, $y, $w, $h);
}
}

Added bonus here is the fact that we disabled the possibility for
multiple constructor invocations, and are enforcing constructor argument
invariants (which PHP does not).

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Yasuo Ohgaki
Re: [PHP-DEV] Type variants
March 12, 2017 09:50PM
Hi Michael,

On Sun, Mar 12, 2017 at 7:33 PM, Yasuo Ohgaki <[email protected]> wrote:

> IMO, C# like getter/setter is better though.
>
> http://stackoverflow.com/questions/11159438/looking-
> for-a-short-simple-example-of-getters-setters-in-c-sharp
>

I pasted wrong URL. This URL has better example code.

https://msdn.microsoft.com/en-us/library/w86s7x04.aspx

While DbC is nice, but checks are only performed on dev environment for
maximum performance and acceptable safety. Therefore, developers must
implement mandatory validations at trust boundaries to ensure software
safety.
i.e. Code correctness and security. Your proposal is useful for this.

Please note that, with DbC, caller has responsibility to make correct calls
that
follow contracts. e.g. Caller must use sane parameters for callee. With
this design,
basic objects/functions, that may execute validation code repetitively, can
safely
omit validations for maximum performance as long as contracts are
maintained.

I'm not against to have method/feature that validates object, but it would
be
better to implement DbC support, then runtime object validation support.
Otherwise,
users would design poor performance objects that execute validation code
repetitively.

Regards,

--
Yasuo Ohgaki
yohgaki@ohgaki.net
Michael Vostrikov
Re: [PHP-DEV] Type variants
March 13, 2017 06:20AM
2017-03-12 23:01 GMT+05:00 Fleshgrinder <[email protected]>:

> As I said already, there is no problem if you just change the direction
> of the inheritance.
>

Ok, how to inherit Rectangle, Square, Rhomb, all of which are
Parallelogram? In your example Rectangle knows restrictions of Square and
any Rectangle is instance of Square. It does not match domain model.


2017-03-13 1:40 GMT+05:00 Yasuo Ohgaki <[email protected]>:

> I pasted wrong URL. This URL has better example code.
>
> https://msdn.microsoft.com/en-us/library/w86s7x04.aspx
>
> Getters/setters is a good feature, I'd like them to be in PHP, but they
should be placed in some classes. What are these classes? We still cannot
use all squares as rectangles and some rectangles as squares without
questions. And if we already have one $rectangle with w == h, we cannot
just use it as square, we must create new object based on $rectangle data.
Sorry, only registered users may post in this forum.

Click here to login