Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task Handler arrow function property names are sometimes an empty string #453

Closed
2 tasks
tegefaulkes opened this issue Sep 27, 2022 · 16 comments
Closed
2 tasks
Assignees
Labels
development Standard development r&d:polykey:supporting activity Supporting core activity

Comments

@tegefaulkes
Copy link
Contributor

tegefaulkes commented Sep 27, 2022

Specification

In the NodeManager we make use of 3 handlers with the task system. Their handler IDs are public read only properties that are public readonly handlerId = '${this.constructor.name}.${this.handler.name}' as HandlerId. this.handler is an async arrow function used as a handler for a task. The handlerId should be 'NodeManager.handler'.

The problem is, in some cases the this.handler.name has the value of '' as an empty string. The weird thing is, in a simple test where we just construct the NodeManager and check it we get the expected values. When we do more complex tests within the nodes domain we see the empty strings resulting in errors.

My first guess is it's the same decorator problem we had to fix for the this.constructor.name when we switched to SWC. I'm guessing when we start the NodeManager it overwrites the property names? More exploration on this is needed.

Additional context

Tasks

  1. Determine the cause of the problem.
  2. Fix property names so the are not empty strings.
@tegefaulkes tegefaulkes added the development Standard development label Sep 27, 2022
@CMCDragonkai CMCDragonkai changed the title Fix property.name being an empty string Task Handler arrow function property names are sometimes an empty string Sep 29, 2022
@CMCDragonkai
Copy link
Member

CMCDragonkai commented Jul 10, 2023

Ok so with an async arrow function, one must be aware that the arrow function this does exist by default. Instead it is bound to the parent context.

Problem is... what is the "parent closure" of an arrow function? Well usually it is whatever is defining it.

But if you're defining it in a class... then this could mean what exactly?

Let's try this:

class X {
  static a () {
    console.log('1', this.constructor.name);
    console.log('2', this.name);
  }
  b = () => {
    console.log('3', this.constructor.name);
    // @ts-ignore
    console.log('4', this.name);
    console.log('5', this.c);
    console.log('6', this.b.name);
  };
  c = 3;
}

console.log(X.a());
const x = new X();
console.log(x.b());

Running it gives us:

1 Function
2 X
undefined
3 X
4 undefined
5 3
6 b

Therefore in static functions, the this is the class, while in the arrow function, the this is the instance.

So for this.handler.name to become an empty string, the only possibility is either due to compilation of tsc or swc. And possibly a use of a decorator, either class decorator or method/property decorator or a mix of these issues.

@CMCDragonkai
Copy link
Member

My tests show that this shouldn't happen. With swc or otherwise.

If it does still show up... we may just change the handler name and hardcode it instead.

@CMCDragonkai
Copy link
Member

I'm just thinking there could be an ordering issue with:

public readonly handlerId = '${this.constructor.name}.${this.handler.name}' as HandlerId

That seems like something that may just need to be inlined wherever it is used.

@CMCDragonkai
Copy link
Member

@tegefaulkes I can't find anywhere in the code where we are doing this, as in setting it as a property. Is this issue even relevant anymore?

@CMCDragonkai
Copy link
Member

Ok I see it like:

  public readonly checkSeedConnectionsHandlerId: TaskHandlerId =
    `${this.basePath}.${this.checkSeedConnectionsHandler.name}.checkSeedConnectionsHandler` as TaskHandlerId;

I think this can be remove in favour of inlining this sort of stuff. The whole idea is that his is supposed to be set when the instance is created. If you want to do this sort of stuff, prefer setting it in the constructor instead, or even just dynamically created in the functions themselves.

In fact the usage of public readonly properties that are somewhat dynamic seems kind of misuse, and can be easily confused.

@CMCDragonkai CMCDragonkai added the r&d:polykey:supporting activity Supporting core activity label Jul 10, 2023
@CMCDragonkai
Copy link
Member

In keys/CertManager, this was done as:

keys/CertManager.ts
15:import type { CertId, TaskHandlerId, TaskId } from '../ids/types';
138:  protected renewCurrentCertHandlerId: TaskHandlerId =
139:    `${this.constructor.name}.renewCurrentCert` as TaskHandlerId;

So I think hardcoding it, with only this.constructor.name is better.

@CMCDragonkai
Copy link
Member

This is a quick fix @tegefaulkes.

@tegefaulkes
Copy link
Contributor Author

We're just going to hard-code the handler IDs now just to keep it simple. This should be resolved once we make this change to all handler IDs.

@CMCDragonkai
Copy link
Member

Seems like constructor name works fine. But just hardcode the name of the handler.

@CMCDragonkai
Copy link
Member

Should have this in the documentation too.

@CMCDragonkai
Copy link
Member

@tegefaulkes if we have decided to just hardcode the handler IDs, then you can close this (technically a workaround, not a fix but whatever).

@CMCDragonkai
Copy link
Member

CMCDragonkai commented Feb 20, 2024

But make sure it's applied all over the place. Should not have any inconsistency. Commit message should refer to this issue #453 for background context.

@amydevs
Copy link
Member

amydevs commented Feb 22, 2024

From what I understand, this is a similar problem that React anonymous components have: https://julesblom.com/writing/component-displayname

The solution for dealing with it there is just to hardcode the fn component displayName, no other way.

@amydevs
Copy link
Member

amydevs commented Feb 22, 2024

I've found one last place that the function.name is used in Discovery.ts:

public readonly discoverVertexHandlerId =
    `${this.constructor.name}.${this.discoverVertexHandler.name}.discoverVertexHandlerId` as TaskHandlerId;

Just to clarify, is this meant to be just ${this.constructor.name}.discoverVertexHandler or ${this.constructor.name}.discoverVertexHandler.discoverVertexHandlerId?

Because the naming convention for all of these TaskHandlerIds seem to be ${this.constructor.name}.${function_name}

@tegefaulkes
Copy link
Contributor Author

It used to be ${this.constructor.name}.${this.discoverVertexHandler.name} but was changed to ${this.constructor.name}.${this.discoverVertexHandler.name}.discoverVertexHandlerId as a stop gap measure to fix a bug where the .names were undefined resulting in conflicting handlerIds.

It should just be the constructorName.handlername now.

amydevs added a commit that referenced this issue Feb 22, 2024
…no longer use the `name` property of the handler function due to #453
@amydevs
Copy link
Member

amydevs commented Feb 22, 2024

THis has been fixed by 80ac79d

@amydevs amydevs closed this as completed Feb 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
development Standard development r&d:polykey:supporting activity Supporting core activity
Development

No branches or pull requests

3 participants