Page MenuHomePhabricator

Composite objects are esentially broken because of recent Eolian regressions
Open, Showstopper IssuesPublic

Description

Recent changes to Eolian essentially broke Composite objects in a multitude of ways.

The problematic change is that normal classes are no longer allowed in the interface list. So for example the below no longer works:

class Image {}

// Results in an error
class Button_Image extends Button implements Image {}

There's no ugly way of doing it, or a weird way of doing it, you just absolutely can't.

What I assume is the recommended way around this (edit: later confirmed by @bu5hm4n on IRC) is to split Image above into an interface. So essentially change the above to:

interface Image_Interface {}

class Image implements Image_Interface {}

class Button_Image extends Button implements Image_Interface{}

This is however problematic for a few reasons:

  1. I sometimes can't split something to an interface, for example: what if Image is already a released API outside of our control? E.g. I'm building my own widget and Image is implemented libefl.so? Am I just not able to composite it then?
  2. Does splitting an already existing class into an interface break API? To be honest, I don't know, but this is a concern.
  3. Even if I can split into an interface, it's a lot of redundant work to have to split every class to an interface.
  4. What if Image was defined as class Image implements Image_Interface, Another_Interface? So now whenever I change an object that's used as a composite I need to change everything that uses it? It takes away a lot of the automatic nature composite objects which is the whole point of having them.
  5. Having an interface for every little thing makes the inheritance tree unnecessarily complex and confusing.

Furthermore, by doing it this way, we are essentially discouraging having any properties/methods on classes at all, and instead telling people: when you want to create a class you actually need to create a class and an interface.

I'm not sure I know what's the correct thing to do here, but I don't think dumbing down Eo and increasing the burden on widget developers is the way to go. A couple of alternatives:

  1. Not have composite objects at all (though I like them and think they are useful).
  2. Allow composite objects that are actual objects (and change the syntax to be like T8183) as to have them distinct in the call graph, and then in bindings just have something like: btn_img->image_obj->file_set() (for the example above). For this we would need API in eolian to name the composite objects.

I'm sure there are others, just none come to mind at the moment. Any thoughts?

Edit: More important comments:

  1. either way, whatever we decide needs to also be mirrored in eo, and not just blocked in Eolian but allowed in eo.
  2. I can show you examples where this becomes hellish. It's really apparent with the Efl.Ui.Text class and what it inherits from, which lean on composite objects heavily.

Another edit:
Just another example where the "split into a separate interface" fails:
Assuming you have a class A that has 3 unrelated different properties: x, y an z. If I was to split to a different interface I would either have to create 3 separate interfaces that aren't really reusable or needed elsewhere, or essentially create InterfaceA which is the class just in an interface form, which is essentially a manual and ugly version of how it used to be. Either way, we've solved nothing and it's quite bad.

tasn created this task.Aug 28 2019, 6:27 AM
tasn updated the task description. (Show Details)Aug 28 2019, 6:41 AM
tasn updated the task description. (Show Details)Aug 28 2019, 6:45 AM
tasn updated the task description. (Show Details)Aug 28 2019, 8:42 AM
tasn updated the task description. (Show Details)Aug 29 2019, 5:47 AM
raster triaged this task as Showstopper Issues priority.Sep 10 2019, 8:34 AM
raster added a subscriber: raster.

btw... this is horribly broken. to the point it's a showstopper.

why?

e.g. efl_core_command_line.eo - this mixin leaks memory because it has no destructor. there is char *string_command and Eina_Array *command in the mixin struct and no code to free these. i have also spotted the same issue efl_gfx_path.eo where double *points and Efl_Gfx_Path_Command *commands and char *path_data all will leak as there is no destructor. i imagine this is in many other places.

the problem is if you try and add a destructor with extends Efl.Object and implements { Efl.Object.destructor; } then eolain barfs not allowing this. this just can't be right. you HAVE to be able to implement destructors (and constructors) for a mixin. it's a fundamental design flaw that has REAL consequences (leaking memory allover the place because you CANNOT implement any kind of cleanup mechanism at all).

tasn added a comment.Sep 10 2019, 8:41 AM

Speaking of mixins, it also breaks mixins in other ways. Now you can't override other object functions, not just Efl.Base's, which is almost the whole point of having a mixin in the first place.

tasn renamed this task from Composite objects are esentially broken because of recent Eolian regressions to Composite objects and mixins are esentially broken because of recent Eolian regressions.Sep 10 2019, 8:41 AM

oh wait... to be non-obvious you have to use requires not extends... this is kind of weird... why?

tasn renamed this task from Composite objects and mixins are esentially broken because of recent Eolian regressions to Composite objects are esentially broken because of recent Eolian regressions.Sep 10 2019, 8:45 AM

OK, so it can be done with requires. It still doesn't solve the original composite issue this ticket is about.

q66 added a subscriber: q66.Sep 12 2019, 7:52 AM

@raster that's because requires is not extends, requires pretty much specifies a list of classes that are required to be in inheritance tree of the thing using the mixin; by specifying it, you tell eolian that it's guaranteed it'll be there, and the mixin can safely implement it.

zmike added a subscriber: zmike.Sep 12 2019, 7:57 AM

Can you clarify some real world cases where class implements class would be required to solve a problem that class implements interface would not be capable of?

tasn added a comment.Sep 12 2019, 8:05 AM
In T8184#142185, @q66 wrote:

@raster that's because requires is not extends, requires pretty much specifies a list of classes that are required to be in inheritance tree of the thing using the mixin; by specifying it, you tell eolian that it's guaranteed it'll be there, and the mixin can safely implement it.

Yeah, we understand what "requires" means, as in why the name is there. Though how is it different than implements? As that's exactly what's going on here?

tasn added a comment.EditedSep 12 2019, 8:29 AM
In T8184#142187, @zmike wrote:

Can you clarify some real world cases where class implements class would be required to solve a problem that class implements interface would not be capable of?

It's not only about capabilities (though also much about it), it's also about how the latter forces you to poorly design your classes and increases the workload on developers.

As I said in my original post, I'm OK with dropping composite objects, or heck, even significantly change them so they behave more like efl_part (efl_comp_get(b, A_CLASS)) rather than the way they are. I'm open to having other solutions, it's just that the current one essentially renders them useless for many use-cases, and again, forces bad design.

Here are some of the major issues I have in mind. This list is probably not exhaustive and I'm sure we can find more issues.

You need to split everything into an interface

Because you can only call functions on composite objects if they are exposed via interfaces, you essentially need to make every public function of your class into an interface. So now, instead of creating Efl.Canvas.Text, you need to create Efl.Canvas.Text.Object and Efl.Canvas.Text.Object_Interface with the latter holding all of the functions because it may be used as a composite object. It's a lot more work to have to do that, and it drives to crazy design decisions.

One objection you can make to the above is: "well, you should have reusable interfaces for everything". To that I would say not always. Sure if you have reusable stuff, cool. But something functions are really just specific to a certain object, and more than that, some of them are just 1 here and 1 there, so you end up either just having the full interface object specific, or a lot of small ones that have no logical grouping/sense to them.

So you forced a bad design.

Even if it wasn't a bad design (though it is), it's very annoying to have to create a few interfaces for every class you want to create.

You need to manually include all of the interfaces in all of the inheritance tree + specific them

For example, if you have A implements I1, I2, ..., I7 and now you want to do B composites A you would need to do B composites I1, I2, ..., I7 rather than get that for free as it should. It's tedious and error-prone, but it's also opaque, because now you're losing the meaning ("this object is a composite of the text object").

So essentially, by forcing all of this manual work, you're also losing the actual intention of the programmer.

Because you are losing the intention, there's another side-effect, if A is ever updated, you'd have to update B manually, an every object that uses A as a composite object. Interfaces are not added often, but they are added!

efl_isa won't work on the class

Sure, you can argue that someone can just check that all of the correct interfaces are implemented, but it's not a real solution, because sometimes you want to know he object is really of the class you want to check (again, losing semantics). For example, the Text.Cursor object only works on Canvas.Text objects, but without this, they can't be associated safely and correctly.

Finishing words

As I said, there are probably more reasons, but the loss of semantics, the added complexity, and the forcing people to have bad design are already good enough. I'm OK with changing composite objects to be more like efl_part, but the way they are now, they make the code worse, not better, and they force everyone to make their code worse.

Could maybe the people who introduced this breaking change explain their reasoning rather than me having to explain why it breaks things?
Edit: or maybe refer me to the relevant discussion? Notes? Mailing list thread? So I can learn more about the thinking and pros/cons that went into it rather than forcing that person to repeat it here. Thanks!

zmike added a subscriber: cedric.Sep 12 2019, 10:10 AM

Thanks for taking the time to chat with me on IRC today. I think I have a better idea on some of the questions you've posed, but I think some of my points weren't as clear as they could have been, and some of the questions and claims that you've made here are still a little nebulous to me.

  1. I sometimes can't split something to an interface, for example: what if Image is already a released API outside of our control? E.g. I'm building my own widget and Image is implemented libefl.so? Am I just not able to composite it then?

I'm unclear how the current composite mechanisms don't allow for this?

  1. Does splitting an already existing class into an interface break API? To be honest, I don't know, but this is a concern.

I'm not sure how this is a concern; perhaps I'm not thinking of the same case that you are. There's no need to split the class; an interface could be created with the same method/property without any issues as long as the original class didn't break its API.

  1. Even if I can split into an interface, it's a lot of redundant work to have to split every class to an interface.

There's no requirement that classes must be split into interfaces.

  1. What if Image was defined as class Image implements Image_Interface, Another_Interface? So now whenever I change an object that's used as a composite I need to change everything that uses it? It takes away a lot of the automatic nature composite objects which is the whole point of having them.

Can you elaborate on exactly which changes you're referring to?

  1. Having an interface for every little thing makes the inheritance tree unnecessarily complex and confusing.

This is an opinion. Generally speaking, in OOP you have a lot of interfaces. @segfaultxavi we had a chat about this recently, I think?

In T8184#142190, @tasn wrote:
In T8184#142187, @zmike wrote:

Can you clarify some real world cases where class implements class would be required to solve a problem that class implements interface would not be capable of?

It's not only about capabilities (though also much about it), it's also about how the latter forces you to poorly design your classes and increases the workload on developers.

As I said in my original post, I'm OK with dropping composite objects, or heck, even significantly change them so they behave more like efl_part (efl_comp_get(b, A_CLASS)) rather than the way they are. I'm open to having other solutions, it's just that the current one essentially renders them useless for many use-cases, and again, forces bad design.

To be clear, this is your opinion and not a fact. I'm not convinced of this.

Here are some of the major issues I have in mind. This list is probably not exhaustive and I'm sure we can find more issues.

  1. You need to split everything into an interface

    Because you can only call functions on composite objects if they are exposed via interfaces, you essentially need to make every public function of your class into an interface. So now, instead of creating Efl.Canvas.Text, you need to create Efl.Canvas.Text.Object and Efl.Canvas.Text.Object_Interface with the latter holding all of the functions because it may be used as a composite object.

I recall having a discussion recently about composition using only interfaces with @bu5hm4n and @cedric; they can probably frame this more concisely than I can.

It's a lot more work to have to do that, and it drives to crazy design decisions.

This is opinion.

One objection you can make to the above is: "well, you should have reusable interfaces for everything". To that I would say not always. Sure if you have reusable stuff, cool. But something functions are really just specific to a certain object, and more than that, some of them are just 1 here and 1 there, so you end up either just having the full interface object specific, or a lot of small ones that have no logical grouping/sense to them.

From the perspective of designing API with intent vs brevity, we've made a decision to go with intent. See also Efl.File_Save, where a considerable amount of time was spent deciding whether and how to split this from Efl.File. This is primarily an API design issue, which we tend to direct with documentation; @segfaultxavi do you have anything to add here?

So you forced a bad design.

This is also opinion.

Even if it wasn't a bad design (though it is), it's very annoying to have to create a few interfaces for every class you want to create.

This is also opinion as well as a sweeping generalization for a hypothetical scenario with no clearly-defined specifications.

  1. You need to manually include all of the interfaces in all of the inheritance tree + specific them

    For example, if you have A implements I1, I2, ..., I7 and now you want to do B composites A you would need to do B composites I1, I2, ..., I7 rather than get that for free as it should. It's tedious and error-prone, but it's also opaque, because now you're losing the meaning ("this object is a composite of the text object").

    So essentially, by forcing all of this manual work, you're also losing the actual intention of the programmer.

    Because you are losing the intention, there's another side-effect, if A is ever updated, you'd have to update B manually, an every object that uses A as a composite object. Interfaces are not added often, but they are added!

We discussed this a bit on IRC, but I don't think I was making my points as clearly as I should have. Ping @cedric for hopefully clearer phrasing.

  1. efl_isa won't work on the class

    Sure, you can argue that someone can just check that all of the correct interfaces are implemented, but it's not a real solution, because sometimes you want to know he object is really of the class you want to check (again, losing semantics). For example, the Text.Cursor object only works on Canvas.Text objects, but without this, they can't be associated safely and correctly.

I'm confused by this point: my interpretation here is that you're saying someone has created a class A which may or may not implement all the features of class B, and the user wants to verify this at runtime? Couldn't an internal class (e.g., Efl.Ui.Internal.Text.Interactive) solve this?

  1. Finishing words

    As I said, there are probably more reasons, but the loss of semantics, the added complexity, and the forcing people to have bad design are already good enough. I'm OK with changing composite objects to be more like efl_part, but the way they are now, they make the code worse, not better, and they force everyone to make their code worse.

I'm not sure anyone is genuinely interested in another efl_part-like API...

Could maybe the people who introduced this breaking change explain their reasoning rather than me having to explain why it breaks things?
Edit: or maybe refer me to the relevant discussion? Notes? Mailing list thread? So I can learn more about the thinking and pros/cons that went into it rather than forcing that person to repeat it here. Thanks!

There were a number of tickets created on this topic, such as https://phab.enlightenment.org/T7240.

Let's try to focus less on blaming specific people for decisions that were made as a group and try to instead work towards a solution that at least a large majority (ideally everyone, however) can be satisfied with.

I would think that overexposing API from a class and have it automatically propagated everywhere would not be your favored choice for internal object. It seems to me more logical to carefully choose which API is exposed and only expose those out as they then require to be forever supported (Made the mistake to use composite on elementary combobox and overexpose to many API unknowingly, so I am very cautious of the argument of automatic propagation for composite object). Also extending the interface supported by a class should not break API of that said class and its inheriting class.

tasn added a comment.Sep 12 2019, 10:53 AM

Hey,

Thanks for replying, though as I said in many of my replies below: please reread what I said. I obviously at least have a passing understanding of this topic, so if what I write looks like it can be easily dismissed, assume you misread rather than assuming I made a rookie mistake on every point.

The rest you just reply to with "this is an opinion". Yeah, I'm stating my opinions, in addition to laying out the facts.

In T8184#142191, @zmike wrote:

Thanks for taking the time to chat with me on IRC today. I think I have a better idea on some of the questions you've posed, but I think some of my points weren't as clear as they could have been, and some of the questions and claims that you've made here are still a little nebulous to me.

  1. I sometimes can't split something to an interface, for example: what if Image is already a released API outside of our control? E.g. I'm building my own widget and Image is implemented libefl.so? Am I just not able to composite it then?

I'm unclear how the current composite mechanisms don't allow for this?

The main part of this comment has nothing to do with composites, read it as it is. Sometimes you can't split something to an interface. If you have a class that has already been released with functions on it. You can't, later on, move it to an interface. Well, at least not without breaking all of classes depending on it. So once you put a function on a class, it's there for good.

Now, because with the existing system you can't later on break such classes, you won't be able to composite this object, as you won't be able to use these functions. I hope it's clear.

  1. Does splitting an already existing class into an interface break API? To be honest, I don't know, but this is a concern.

I'm not sure how this is a concern; perhaps I'm not thinking of the same case that you are. There's no need to split the class; an interface could be created with the same method/property without any issues as long as the original class didn't break its API.

Again, please reread what I said. "An already existing class" and breaking API indicate it's obviously about released classes, so you can't split it to an interface because all of the .eo files that depend on it refer to that function by name, e.g. Efl.Object.constructor.

  1. Even if I can split into an interface, it's a lot of redundant work to have to split every class to an interface.

There's no requirement that classes must be split into interfaces.

Again, please reread what I said. If you can only expose functionality using interfaces when using composite objects, if an object is ever to become a composite object, you'd need to have all of its functionality exposed. So effectively, if you ever want to sanely composite objects, you need all of the classes to always have all of their functions that would possibly be used in a composite-object setting be exposed in an interface. So yes, there is a de facto requirement.

  1. What if Image was defined as class Image implements Image_Interface, Another_Interface? So now whenever I change an object that's used as a composite I need to change everything that uses it? It takes away a lot of the automatic nature composite objects which is the whole point of having them.

Can you elaborate on exactly which changes you're referring to?

Again, we already discussed this on IRC (and a few times above).

If you have a class A implements I1, I2 and B that is composited of A. With the existing suggestion you would do B implements I1, I2. If you change A to be A implements I1, I2, I3, you'd now need to manually change B's implement section too, and every other object that used A as a composite object, in order to get this new functionality. Sometimes you can do it (so if B is inside the efl), but sometimes you can't, if B is in a 3rd party library. Then users of that library would need to wait until the maintainer also *manually* updates that one, intead of getting it for free.

  1. Having an interface for every little thing makes the inheritance tree unnecessarily complex and confusing.

This is an opinion. Generally speaking, in OOP you have a lot of interfaces. @segfaultxavi we had a chat about this recently, I think?

Confusing, yes, that's an opinion, though I think a widely held one. Complex? That's a fact, when you change a class with no interfaces to a class with 10, it's a more complex inheritance tree (you could argue that the class itself is simpler, but I'd disagree).

In T8184#142190, @tasn wrote:
In T8184#142187, @zmike wrote:

Can you clarify some real world cases where class implements class would be required to solve a problem that class implements interface would not be capable of?

It's not only about capabilities (though also much about it), it's also about how the latter forces you to poorly design your classes and increases the workload on developers.

As I said in my original post, I'm OK with dropping composite objects, or heck, even significantly change them so they behave more like efl_part (efl_comp_get(b, A_CLASS)) rather than the way they are. I'm open to having other solutions, it's just that the current one essentially renders them useless for many use-cases, and again, forces bad design.

To be clear, this is your opinion and not a fact. I'm not convinced of this.

It forces you to take a very specific path and split more than you normally would. It forces you to have "reusable interfaces" that are not really reusable but are just class specific. It forces you to choose between having an interface that just holds all the functions that would be on the class and having a lot of small interfaces because the class has unrelated functions, or group things together that don't make sense.

So yeah, I disagree.

Here are some of the major issues I have in mind. This list is probably not exhaustive and I'm sure we can find more issues.

  1. You need to split everything into an interface

    Because you can only call functions on composite objects if they are exposed via interfaces, you essentially need to make every public function of your class into an interface. So now, instead of creating Efl.Canvas.Text, you need to create Efl.Canvas.Text.Object and Efl.Canvas.Text.Object_Interface with the latter holding all of the functions because it may be used as a composite object.

I recall having a discussion recently about composition using only interfaces with @bu5hm4n and @cedric; they can probably frame this more concisely than I can.

The above is a fact, there's nothing to add.

It's a lot more work to have to do that, and it drives to crazy design decisions.

This is opinion.

This is not an opinion. It's a lot more work to do it.

Crazy design decisions: OK, if you remove the word crazy it's a fact. Though what do you think on the point just before this? Because what I described there is crazy, and you haven't replied to that one. If you agree to that, you agree with this opinion.

One objection you can make to the above is: "well, you should have reusable interfaces for everything". To that I would say not always. Sure if you have reusable stuff, cool. But something functions are really just specific to a certain object, and more than that, some of them are just 1 here and 1 there, so you end up either just having the full interface object specific, or a lot of small ones that have no logical grouping/sense to them.

From the perspective of designing API with intent vs brevity, we've made a decision to go with intent. See also Efl.File_Save, where a considerable amount of time was spent deciding whether and how to split this from Efl.File. This is primarily an API design issue, which we tend to direct with documentation; @segfaultxavi do you have anything to add here?

This is not the point I was making, again, reread what I said (and we discussed it on IRC). Let me give you two (out of many) concrete example from the text world. These two properties are on the Raw_Editable text object: @property password_mode and @property input_panel_show_on_demand. These are both specific to the Raw_Editable text object, and are not used by any other object in the efl (that don't inherit/implement/composite this object). Should these be an interface or two? If one, these are unrelated and it's the class replacing interfaces I was describing. If two, wait until I give you 10 other unrelated functions that don't have any logical grouping other than all being relevant to an editable entry.

So you forced a bad design.

This is also opinion.

Thank you for pointing it out. Let me rephrased, you are forced to the design as described above.

Even if it wasn't a bad design (though it is), it's very annoying to have to create a few interfaces for every class you want to create.

This is also opinion as well as a sweeping generalization for a hypothetical scenario with no clearly-defined specifications.

It's not hypothetical, I gave you an example above, and I bet my ass that every class in the efl already suffered from the aforementioned bad design, or suffers from the same inability of not supporting compositing because it doesn't.

  1. You need to manually include all of the interfaces in all of the inheritance tree + specific them

    For example, if you have A implements I1, I2, ..., I7 and now you want to do B composites A you would need to do B composites I1, I2, ..., I7 rather than get that for free as it should. It's tedious and error-prone, but it's also opaque, because now you're losing the meaning ("this object is a composite of the text object").

    So essentially, by forcing all of this manual work, you're also losing the actual intention of the programmer.

    Because you are losing the intention, there's another side-effect, if A is ever updated, you'd have to update B manually, an every object that uses A as a composite object. Interfaces are not added often, but they are added!

We discussed this a bit on IRC, but I don't think I was making my points as clearly as I should have. Ping @cedric for hopefully clearer phrasing.

It's very simple:

B composites A - now we know B is made of A.
B composites I1, I2, I3 - we don't know that B is made of A. We were able to do both in the previous design.

To take it to a CS example:
Car composites SteeringWheel - the first above
Car composites Round, Honkable, Suede, Airbag - go figure, intention of the programmer was lost.

  1. efl_isa won't work on the class

    Sure, you can argue that someone can just check that all of the correct interfaces are implemented, but it's not a real solution, because sometimes you want to know he object is really of the class you want to check (again, losing semantics). For example, the Text.Cursor object only works on Canvas.Text objects, but without this, they can't be associated safely and correctly.

I'm confused by this point: my interpretation here is that you're saying someone has created a class A which may or may not implement all the features of class B, and the user wants to verify this at runtime? Couldn't an internal class (e.g., Efl.Ui.Internal.Text.Interactive) solve this?

We talked about it on IRC already and it's clear from the context, but I'll take another jab at explaining this.

B composites A is what you want to do.
When you implement it as B composites I1, I2, I3 (interfaces of A), you lose the ability to do efl_isa(obj_b, A), and again, you lose the intention of the programmer.

Some classes, like Cursor, are helper classes that are designed to work with a specific object. They interact using private API rather than public API for many reasons, for example efficiency (to avoid eo calls) but not only. They need to work only on a textblock object (or something that inherits from it), and they need to be able to easily know if an object is a textblock in order to do these private calls. However, if you composite using interfaces and not object, they can't because efl_isa is broken.

  1. Finishing words

    As I said, there are probably more reasons, but the loss of semantics, the added complexity, and the forcing people to have bad design are already good enough. I'm OK with changing composite objects to be more like efl_part, but the way they are now, they make the code worse, not better, and they force everyone to make their code worse.

I'm not sure anyone is genuinely interested in another efl_part-like API...

"This is an opinion"...

Also, I disagree.

Could maybe the people who introduced this breaking change explain their reasoning rather than me having to explain why it breaks things?
Edit: or maybe refer me to the relevant discussion? Notes? Mailing list thread? So I can learn more about the thinking and pros/cons that went into it rather than forcing that person to repeat it here. Thanks!

There were a number of tickets created on this topic, such as https://phab.enlightenment.org/T7240.

Thanks.

Let's try to focus less on blaming specific people for decisions that were made as a group and try to instead work towards a solution that at least a large majority (ideally everyone, however) can be satisfied with.

No one was talking about blame, as I said, I want to inform myself on the thinking that went into it so we can have a better discussion.

tasn added a comment.Sep 12 2019, 11:03 AM

I would think that overexposing API from a class and have it automatically propagated everywhere would not be your favored choice for internal object. It seems to me more logical to carefully choose which API is exposed and only expose those out as they then require to be forever supported (Made the mistake to use composite on elementary combobox and overexpose to many API unknowingly, so I am very cautious of the argument of automatic propagation for composite object). Also extending the interface supported by a class should not break API of that said class and its inheriting class.

Breaking API: I already replied to that in my most recent reply to zmike (which I posted at the same time as you), this is not what I said. I was talking about adding interfaces. Also I didn't say it was breaking, I said it would require people to extend *all* the inheriting classes to get it.

As for automatically propagating: I'm not against that, but this is not the right mechanism for that:

First of all, if you want to choose, you can just add a way to define it in the eolian file - define which you are supporting and which you aren't forwarding. It's only for bindings anyway, because for the eo object it would just work anyway because you fellas only blocked it in eolian and not in eo. This doesn't mean you need to force separation of interfaces. Also, what if you have, in this interface a function you do want and a function you don't? What if one object wants to expose one thing, and another one another?

Using interfaces is a solution, but it's not necessarily a good one.

Also, the more I think about it, the more it seems like an efl_part API like described above could maybe be the solution to all of this, and in bindings have obj->text_comp->text_set().

In T8184#142195, @tasn wrote:

Also, the more I think about it, the more it seems like an efl_part API like described above could maybe be the solution to all of this, and in bindings have obj->text_comp->text_set().

I think this is a very bad idea as it doesn't force whoever provide it to actually implement a proper wrapper and will most likely result in lazy behavior of directly exposing entire object. If in your situation you think something close to part is a good idea, maybe part is the solution you are looking for.

q66 added a comment.EditedSep 12 2019, 12:00 PM
In T8184#142189, @tasn wrote:
In T8184#142185, @q66 wrote:

@raster that's because requires is not extends, requires pretty much specifies a list of classes that are required to be in inheritance tree of the thing using the mixin; by specifying it, you tell eolian that it's guaranteed it'll be there, and the mixin can safely implement it.

Yeah, we understand what "requires" means, as in why the name is there. Though how is it different than implements? As that's exactly what's going on here?

Stuff in the other sections is put within the object's inheritance, stuff in requires is not, the requires section is never used when defining the mixin; it's just a guarantee you provide.

tasn added a comment.Sep 12 2019, 12:54 PM
In T8184#142195, @tasn wrote:

Also, the more I think about it, the more it seems like an efl_part API like described above could maybe be the solution to all of this, and in bindings have obj->text_comp->text_set().

I think this is a very bad idea as it doesn't force whoever provide it to actually implement a proper wrapper and will most likely result in lazy behavior of directly exposing entire object. If in your situation you think something close to part is a good idea, maybe part is the solution you are looking for.

Oh, the intention is to expose the entire object. As I said, up for discussion, but this is off the topic.

tasn added a comment.Sep 12 2019, 12:57 PM
In T8184#142203, @q66 wrote:
In T8184#142189, @tasn wrote:
In T8184#142185, @q66 wrote:

@raster that's because requires is not extends, requires pretty much specifies a list of classes that are required to be in inheritance tree of the thing using the mixin; by specifying it, you tell eolian that it's guaranteed it'll be there, and the mixin can safely implement it.

Yeah, we understand what "requires" means, as in why the name is there. Though how is it different than implements? As that's exactly what's going on here?

Stuff in the other sections is put within the object's inheritance, stuff in requires is not, the requires section is never used when defining the mixin; it's just a guarantee you provide.

Essentially the same as implements when it comes to Eo. I don't think it's actually used. Though anyhow, you "require" the class in order to "implement" a function from it. I guess the difference is that you don't expose it as if the class is implemented (e.g. to bindings), though in practice, whoever is using this mixin will already have whatever classes the mixin implements functions from there already.

Anyhow, let's stop this discussion, it's off the main point. Happy to have it somewhere else, but it's hard enough to discuss things on phab, even without unrelated discussions.

tasn added a comment.Sep 17 2019, 6:02 AM

And... The sound of silence again... :|

Maybe because we are all confused by what you actually want to talk about and what you mean. At least I am. I do not understand what is the problem you want this task to address and every time I reread your message I feel more confusion. Maybe you should try to explain in a more focused way what is the trouble you have and how you would want it to be fixed?

tasn added a comment.Sep 18 2019, 4:04 AM

If you are confused you should ask, not disappear...

Anyhow, I'm not sure how to explain it in a simpler manner, I can try again if you need me to, but could you maybe ask leading questions about what you didn't understand?

Thanks!

Maybe try again to explain what is the problem you are facing, why it is a problem and how you want it solved. That should be a starting point to clarify the topic.

tasn added a comment.Sep 21 2019, 8:20 AM

I think I explained it very well in previous posts, but maybe a concise summary would be:

I have a class called Efl.Canvas.Text, it has functions on it.
I have a class called Efl.Ui.Text which has Efl.Canvas.Text as a composite object.
Because of this regression you can't access Efl.Canvas.Text's functions on Efl.Ui.Text.
You therefore have to move every function to an interface. The thing is, because of this limitation you actually can't have functions on any class ever because it could potentially be used in a composite object and if you want its classes to ever be reachable they have to be on interfaces.

Splitting functions to interfaces doesn't always make sense (see my most recent email to e devel where I'm asking to help with that because I've given up on this issue ever being solved. Title: "RFC: Text interface + advice regarding interface splitting").
So you end up with a shit design and a lot of redundant work if you ever want to use classes as a composite. If you don't design this way, you're essentially rendering composites useless, because if no one designs with this in mind, you won't even be able to use them.

jeyzu added a subscriber: jeyzu.Nov 7 2019, 5:30 PM

The problem exposed by tasn is pretty clear,
eo implements a straight forward object composition : an object component merged into another composite object exposes it's methods.
That's a standard and expected OO behavior.

Latest changes in Eolian do not allow that, you now need to create an interface from the component object that has to be implemented by the composite object.
follow up is that if you change the component, you'll have to update all composite object implementing it's interface.

can someone explain why that change in behavior is correct ?