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

How to migrate away from 'nameof'? #117

Open
zapta opened this issue Dec 22, 2024 · 14 comments
Open

How to migrate away from 'nameof'? #117

zapta opened this issue Dec 22, 2024 · 14 comments

Comments

@zapta
Copy link

zapta commented Dec 22, 2024

We have a code similar to the one below where we use nameof to convert arg names to strings. The advantage is that the ide tools are aware of the relation between the function args and nameof's args (e.g. when renaming or linting).

We tried to upgrade to the latest varname version and get a warning that we should use argname() instead but it seems to require the name of the arg a a string which defeats the reason we use varname.

Are we missing anything? What is the use case of argname() if the user requires to provide the arg name string?

def cli(
    cmd_ctx: click.core.Context,
    # Options:
    ftdi_install: bool,
    ftdi_uninstall: bool,
    serial_install: bool,
    serial_uninstall: bool,
):
    """Implements the drivers command."""

    # User should select exactly on of these operations.
    cmd_util.check_exactly_one_param(
        cmd_ctx,
        nameof(ftdi_install, ftdi_uninstall, serial_install, serial_uninstall),
    )
@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

What do you think this will return:

nameof(ftdi_install, ftdi_uninstall, serial_install, serial_uninstall)?

@zapta
Copy link
Author

zapta commented Dec 22, 2024 via email

@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

So then why not just use ["ftdi_install", "ftdi_uninstall", 'serial_install", "serial_uninstall"] directly?

@zapta
Copy link
Author

zapta commented Dec 22, 2024

Because the IDE and tools like linters will not be aware of the association
between the arg ftdi_install and the string 'ftdi_install'. For
example if we rename the arg of if the string has a typo.

@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

I don't get it. If you change, say, ftdi_install to ftdi_install2, then what will the IDE/linters complain about if you do:

def cli(
    cmd_ctx: click.core.Context,
    # Options:
    ftdi_install2: bool,
    ftdi_uninstall: bool,
    serial_install: bool,
    serial_uninstall: bool,
):
    """Implements the drivers command."""

    # User should select exactly on of these operations.
    cmd_util.check_exactly_one_param(
        cmd_ctx,
        ["ftdi_install2", "ftdi_uninstall", "serial_install", "serial_uninstall"),
    )

@zapta
Copy link
Author

zapta commented Dec 22, 2024

The tools will not complain that there is no arg called ftdi_install3, but with nameof() they will. Same if I use an IDE refactoring tool to rename the arg ftdi_uninstall to ftdi_install4, it will not rename also the string 'ftdi_uninstall', but with nameof() it will.

def cli(
    cmd_ctx: click.core.Context,
    # Options:
    ftdi_install2: bool,
    ftdi_uninstall: bool,
    serial_install: bool,
    serial_uninstall: bool,
):
    """Implements the drivers command."""

    # User should select exactly on of these operations.
    cmd_util.check_exactly_one_param(
        cmd_ctx,
        ["ftdi_install3", "ftdi_uninstall", "serial_install", "serial_uninstall"),
    )

@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

I am still confused. Why did you put "ftdi_install3" instead of "ftdi_install2"?

@zapta
Copy link
Author

zapta commented Dec 22, 2024

To demonstrate a mismatch (e.g. a typo) between the arg name and the string. If instead of "ftdi_install3" I use nameof(ftdi_install3), then the tools detect the error statically, in the editor.

@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

I see what you meant. But I am not convinced that nameof should be used for this purpose. But if you do want it to be used this way, you can wrap a version of nameof by yourself using argname:

from varname import argname

def my_nameof(*args):
  return argname('*args')

a = b = 1
my_nameof(a, b)  # ('a', 'b')

@zapta
Copy link
Author

zapta commented Dec 22, 2024

You can look at the code in the link below. All the places that argument fix is mentioned are associated with each other and if I rename one they all change. With strings they are isolated from each other and the tools don't know about the intended association.

https://github.com/FPGAwars/apio/blob/ca5dc994ff7f66b1f752db57bfad3b97a0eb0772/apio/commands/packages.py#L222

@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

What you referred to as "associated" or "isolated" is merely due to the help of the IDE, rather than being based on the code itself.

@zapta
Copy link
Author

zapta commented Dec 22, 2024 via email

@pwwang
Copy link
Owner

pwwang commented Dec 22, 2024

You are correct, and that is the foundation of the IDE. I won’t argue about code style. However, nameof has been deprecated due to its redundancy with argname, and it's quite straightforward to implement it using argname (as I demonstrated in the above example). Another reason for the deprecation is that many people tend to use it incorrectly. In many cases, literal strings are sufficient.

@zapta
Copy link
Author

zapta commented Dec 22, 2024

I implemented my_nameof and it works, thanks.

I just had to rename args to _args to make the tools happy since from their perspective it's an unused argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants