Jump to page: 1 2
Thread overview
September 17

Hi!
I want to change a method Draw on a custom object when the MouseIn event occurs.
This is known as "Change State" of the object: Init -> Hovered.

I want to change the state of an object by changing its class, like this:


this.__vptr = typeid(CLS).vtbl.ptr;

I have read the ABI and am confident in replacing __vptr as long as the classes contain the same fields and the same interfaces.

Example:

// O
//   to!state
// State_Init    : O
//   Draw
// State_Hovered : O
//   Draw
//
// o.to!State_Hovered
// o.to!State_Init

class O
{
  void to(CLS)()
  {
    // if (same fields && same interfaces && same instance size)
    this.__vptr =
      cast(immutable(void*)*)typeid(CLS).vtbl.ptr;
  }
}

State_Init : O
  void Draw() { /* ... */ }

State_Hovered : O
  void Draw() { /* ... */ }

when MouseIn:

  ...
  o.to!State_Hovered();
  ...

when MouseOut:

  ...
  o.to!State_Init();
  ...

It works! But I want to ask how to make this 100% the best of the best?
What should I consider before changing __vptr ?

September 17

On Sunday, 17 September 2023 at 15:05:59 UTC, Vitaliy Fadeev wrote:

>

...

Playground: https://run.dlang.io/is/hjcLCk

September 17

On Sunday, 17 September 2023 at 15:05:59 UTC, Vitaliy Fadeev wrote:

>

It works! But I want to ask how to make this 100% the best of the best?
What should I consider before changing __vptr ?

If that works for you with that constraint of having exact memory layout then it should be ok.

This however is very uncommon pattern and your library users might reject it so keep that in mind if you are going to make public library.

Other than that I would suggest at least to make that cast method to return a shallow copy because messing with "this" ptr can be dangerous (make sure to try it with const objects and optimized release builds before using this everywhere).

An even better (at least safer, in theory) option would be to make "View" or handle struct that wraps an object(pointer) and tracks such transformations.

Of course to think of it now there is yet another opportunity - why not to look for something like ECS then?
Because you seem to already treat your objects purely as data containers, that way you can safely detach data from logic and reduce the scope of your components to keep them focused on one task.
That is up to you of course.

September 17

On Sunday, 17 September 2023 at 17:10:16 UTC, evilrat wrote:

>

On Sunday, 17 September 2023 at 15:05:59 UTC, Vitaliy Fadeev wrote:

>

It works! But I want to ask how to make this 100% the best of the best?
What should I consider before changing __vptr ?

If that works for you with that constraint of having exact memory layout then it should be ok.

No, this is Undefined Behavior and will likely cause you trouble in the future (as in: some very hard to debug bugs may appear).

Better to store the state in the object and select the behavior using a switch on the state.

-Johan

September 21

On Sunday, 17 September 2023 at 15:05:59 UTC, Vitaliy Fadeev wrote:

>

Hi!
I want to change a method Draw on a custom object when the MouseIn event occurs.
This is known as "Change State" of the object: Init -> Hovered.

[...]

Interesting, but why would you want to do it that way? 😳

September 22

On Thursday, 21 September 2023 at 18:19:47 UTC, Imperatorn wrote:

>

On Sunday, 17 September 2023 at 15:05:59 UTC, Vitaliy Fadeev wrote:

>

Hi!
I want to change a method Draw on a custom object when the MouseIn event occurs.
This is known as "Change State" of the object: Init -> Hovered.

[...]

Interesting, but why would you want to do it that way? 😳

Q & A.
You can check the logic.

>

How to increase the battery life of a smartphone?

Reducing operations.

>

How to change the state of a button widget, for example, on mouseover?

By changing the pointer to the Draw method.

>

In addition to Draw, the widget has a Sense method. How to replace all pointers to methods at once?

Replace the pointer with a class.

(It's like a change of state! Exactly Turing's State Machine.)

The object fields are the same. Behavior changes.

The contents of the fields remain in memory. Only the pointer to the method table changes.

Of course, this requires care and forethought.

Perhaps the risks of changing class can be reduced by performing additional checks.

Changing class is a convenient tool. I want to use it.

September 22

On Friday, 22 September 2023 at 02:51:10 UTC, Vitaliy Fadeev wrote:

>

...

 Chip
   id
   name
   Sense()
   Draw()

instance

 chip = new Chip();

compiled to

 chip
   __vtbl   -------------> Chip
   __monitor                 Sense()
   id                        Draw()
   name

I want

chip
  __vtbl --+
  id       |
  name     |
           |-> Chip_Hovered
           |     Sense()
           |     Draw()
           |
           +-> Chip_Hovered
                 Sense()
                 Draw()
September 22

On Friday, 22 September 2023 at 03:33:08 UTC, Vitaliy Fadeev wrote:

>

On Friday, 22 September 2023 at 02:51:10 UTC, Vitaliy Fadeev wrote:

>

...

the most correct

chip
  __vtbl ---+   // one of
  __monitor |
  id        |
  name      |
            |-> Chip           // init
            |     Sense()
            |     Draw()
            |
            |-> Chip_Hovered   // on mouseover
            |     Sense()
            |     Draw()
            |
            +-> Chip_Selected  // on mouseclick
                  Sense()
                  Draw()
September 22

On Friday, 22 September 2023 at 03:33:08 UTC, Vitaliy Fadeev wrote:

>

On Friday, 22 September 2023 at 02:51:10 UTC, Vitaliy Fadeev wrote:

>

...

 Chip
   id
   name
   Sense()
   Draw()

instance

 chip = new Chip();

compiled to

 chip
   __vtbl   -------------> Chip
   __monitor                 Sense()
   id                        Draw()
   name

I want

chip
  __vtbl --+
  id       |
  name     |
           |-> Chip_Hovered
           |     Sense()
           |     Draw()
           |
           +-> Chip_Hovered
                 Sense()
                 Draw()

What I mean is, why not use other language constructs like mixins or inheritance with some mapping for example?

September 22

On Friday, 22 September 2023 at 12:53:28 UTC, Imperatorn wrote:

>

On Friday, 22 September 2023 at 03:33:08 UTC, Vitaliy Fadeev wrote:

>

On Friday, 22 September 2023 at 02:51:10 UTC, Vitaliy Fadeev wrote:

>

...

 Chip
   id
   name
   Sense()
   Draw()

instance

 chip = new Chip();

compiled to

 chip
   __vtbl   -------------> Chip
   __monitor                 Sense()
   id                        Draw()
   name

I want

chip
  __vtbl --+
  id       |
  name     |
           |-> Chip_Hovered
           |     Sense()
           |     Draw()
           |
           +-> Chip_Hovered
                 Sense()
                 Draw()

What I mean is, why not use other language constructs like mixins or inheritance with some mapping for example?

Can you give an example?

« First   ‹ Prev
1 2