Why does _colorize.copy_with() exist?

Why does copy_with exists? Why not use copy.replace which exists for exactly that usecase and is compatible with dataclasses?

6 Likes

copy_with can be typed and doesn’t need an import. It might not be a strong enough reason to keep it, but it’s certainly enough for me to prefer some variant of an object specific copy_with/replace over copy.replace.

But copy_with is also a maintenance burden that needs to be kept correct forever, whereas replace just works. And the typing aspect is irrelevant or in favor of replace since type checker know about that function specifically, which is half of the reason it was introduced.

Saving an import, sure, I guess, but that is imo a very weak argument for keeping around completely redundant code that has a chance to break.

4 Likes

dataclasses depends on copy already so the module is already imported and not using it isn’t saving any import time.

That said I’m not sure why you wouldn’t use dataclasses.replace which doesn’t have the minor issue of needing to import another module.

1 Like

I agree. As I said in my comment:

I don’t think saving an import or lack of typing justifies having a redundant method. But as a user, I can’t help but prefer a copy_with method that’s both easier to reach and is likely typed, giving me both autocomplete and catching errors in the editor.

copy.replace is simply typed as Any:

def replace(obj: _SR, /, **changes: Any) -> _SR: ...

I’ll emphasize again that I’m not arguing to keep the method. A unified protocol like __replace__ is very welcome and was designed to solve this exact problem. It’s unfortunate that it can’t be typed today, but I can live with that.

Somewhat interestingly, mypy will correctly give an error if dataclasses.replace is used with a field that doesn’t exist or with an argument of the wrong type, but won’t give the same error if you use copy.replace.

mypy playground example

[Edit: Original playground link was missing the copy.replace examples.]

That’s a consequence of people arguing for mypy to intentionally be unsound on __replace__ :roll_eyes: