-
Notifications
You must be signed in to change notification settings - Fork 751
Constructor failing argument matching, silently selects default constructor #238
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
Comments
@sigbjorn here is really where bad logic starts and where it should have failed: https://github.com/pythonnet/pythonnet/blob/master/src/runtime/constructorbinder.cs#L84 if (binding == null)
{
// It is possible for __new__ to be invoked on construction
// of a Python subclass of a managed class, so args may
// reflect more args than are required to instantiate the
// class. So if we cant find a ctor that matches, we'll see
// if there is a default constructor and, if so, assume that
// any extra args are intended for the subclass' __init__.
IntPtr eargs = Runtime.PyTuple_New(0);
binding = this.Bind(inst, eargs, kw);
Runtime.Decref(eargs);
if (binding == null)
{
Exceptions.SetError(Exceptions.TypeError,
"no constructor matches given arguments"
);
return null;
}
} |
I'm big minus one on auto-conversion from integer to double or vice-verse. The class could have contained constructors for both types. |
@denfromufa Let's move the discussion on part a) to the pull-request #239. Regarding part b), I'd rather have us fixing this one. I'll check what breaks if we remove the respective section. |
I think that If we remove that section, then sub-classing a .NET class (with arguments) stops working. As indicated by the comment, and some test covering it, it plays a role when you use a .NET class as super class. I am not sure that it's fully working now either, because, if you explicitely pass arguments to the super-class, It should be possible to select precise constructors by just beeing very explicit (not bad). |
Promoting from int->double etc. is standard, even in some strict languages. You got a point that the class could have A(int), A(double) etc, and then we of-course would like the pythonnet to 'do the right thing'. On the other hand, as it is now, it is silently selecting the default contstructor (if such one exists), I think thats is in the order of magnitude a bigger problem, so if we could get a pedandic version that just forces the user to be explicit about types, this is all fine for me, and most other I would think -because then the user is at least notified. |
Ouch, this was not expected. And definitely a huge risk of bugs with the silent default constructor calling. Not allowing inherited constructors seem much less problematic. Additionally, I don't fully understand the problem of checking base class constructors if there already is logic to check the current class constructors (?) I understand that doing automatic type coercion matching can be tricky, but better to just throw an error which describes the received parameter list types and it should be relatively easy to spot the error. Eg
would be a lot better than getting a default value imo |
Oh wow, did not know about this problem. @filmor have you fiddled with it yet? |
I believe this is already fixed in 3.0, but we need a test. |
was: tp_new implementation would call .NET constructor and return a fully constructed object now: Except for some special .NET types tp_new creates uninitialized .NET object, which is later initialized by calling __init__. __init__ is set using type dictionary to a MethodObject, that contains ConstructorInfo[] instead of MethodInfo[] This allows Python to: 1) freely override __init__ 2) when deriving from .NET types call base __init__ (e.g. .NET constructor), and choose the overload as needed fixes pythonnet#238
was: tp_new implementation would call .NET constructor and return a fully constructed object now: Except for some special .NET types tp_new creates uninitialized .NET object, which is later initialized by calling __init__. __init__ is set using type dictionary to a MethodObject, that contains ConstructorInfo[] instead of MethodInfo[] This allows Python to: 1) freely override __init__ 2) when deriving from .NET types call base __init__ (e.g. .NET constructor), and choose the overload as needed fixes pythonnet#238
It was not fixed, but the fix PR is there ) |
was: tp_new implementation would call .NET constructor and return a fully constructed object now: Except for some special .NET types tp_new creates uninitialized .NET object, which is later initialized by calling __init__. __init__ is set using type dictionary to a MethodObject, that contains ConstructorInfo[] instead of MethodInfo[] This allows Python to: 1) freely override __init__ 2) when deriving from .NET types call base __init__ (e.g. .NET constructor), and choose the overload as needed fixes pythonnet#238
was: tp_new implementation would call .NET constructor and return a fully constructed object now: Except for some special .NET types tp_new creates uninitialized .NET object, which is later initialized by calling __init__. __init__ is set using type dictionary to a MethodObject, that contains ConstructorInfo[] instead of MethodInfo[] This allows Python to: 1) freely override __init__ 2) when deriving from .NET types call base __init__ (e.g. .NET constructor), and choose the overload as needed fixes pythonnet#238
was: tp_new implementation would call .NET constructor and return a fully constructed object now: Except for some special .NET types tp_new creates uninitialized .NET object, which is later initialized by calling __init__. __init__ is set using type dictionary to a MethodObject, that contains ConstructorInfo[] instead of MethodInfo[] This allows Python to: 1) freely override __init__ 2) when deriving from .NET types call base __init__ (e.g. .NET constructor), and choose the overload as needed fixes #238
(Version 2.1)
Given .NET class:
then in python:
I am fully aware that super-classes, argument-matching, (automatic) type-conversion,
and bridging the gap between python and .NET (C#) , is very complex.
And providing a full implementation that 'just do the thing we want' is not trivial.
It might be that some of the issues related to sub-classing, as well as argument matching/conversion is related, - but I hope the simple example above illustrates that
some minor improvement at this stage could be quite useful.
There is a few fixes, that could improve this slightly:
(a.) Make simple type-promotion/argument conversion happen during constructor argument matching
(b.) If construction of a .NET object is attempted, and argument match fail, then always raise Type error
I will provide a PR for (a.) since it's a simple fix to verify a simple type-promotion from int->double etc.
Fixing (b.), raise error if no .NET constructor matches the arguments is easy, but will then break the sub-class mechanism. If we knew, by the time we are calling the .NET constructor, that it's a super-class, then we could either have a relaxed matching (as is to day, default to the default-ct, if fail), and then insist on match for all other cases.
After all, providing something that fixes (b.), and at the same time supports, and possibly extends super()/sub-classing mechanism seems harder to me, since we need to know the context in which the .NET object is constructed.
If anyone see a easy solution to (b.) , - as in knowing how to get the context of the .NET class construction, that would be great.
We could then provide a fix where
' you succeed with your intention creating a new object with the supplied parameters, and get the expected result, or we raise Type-exception notifying about the problem'
The text was updated successfully, but these errors were encountered: