Why is QPoint.x() not a property?



  • I am using Qt and Pyside and existing code that uses vectors and points. Typically: foo.x accesses the x component (the attribute.) Now I want to use QPoint. But QPoint.x() is a method (a getter.) Is there a reason it is not a property? So that if foo were a QPoint, I could still access the x component by foo.x. If it is not a property, foo.x returns the unbound method. I don't think subclassing QPoint and making x() a property in the subclass will help me much: everywhere I get a QPoint from Qt I will still have to convert it to either my existing vector class or to my subclass of Qt that has x() a property.



  • What exactly do you mean by proerty? A definition with Q_PROPERTY in a QObject subclass? Simple data containers, like QPoint are no QObjects, so they don't have this logic.



  • QPoint.x wouldn't be a property (in the sense of a QObject Q_PROPERTY), but a public attribute (in the context of C++ classes).

    It would break Qt's design principles to expose otherwise private implementation details as public attributes.

    Oh, and the internal attributes storing the coordinates are named xp and yp. So youwould have to patch QPoint massively including breaking binary compatibility. Your patched Qt would crash with everything else unless you recompile that against your own Qt version.

    It doesn't seem worth the effort.

    I don't know if there are some dirty tricks to achieve that on the python side, though. But from what I know, it behaves very closely to the regular C++ API.



  • Property in programming language:
    http://en.wikipedia.org/wiki/Property_(programming)

    Also see:
    http://en.wikipedia.org/wiki/Uniform_access_principle

    In the theory of programming languages, a property is a method of an object that you can access using data attribute access notation instead of call notation, i.e. "foo.bar" instead of "foo.bar()" .

    Recent Python versions support properties. Objective-C v2.0 supports properties. Earlier Objective-C REQUIRED you to define and call getter methods (method attributes) to access instance variables (data attributes) outside the class definition. For example in Objective-C v1.0 you must use [foo bar] and can't use foo.bar (inside the class definition you use self.bar .) (Note that "[foo bar]" is the Objective-C notation for a call of the foo instance's method named bar.)

    The use case for properties is: you have old code that uses data attribute access notation: foo.bar. You want to decorate access to the data attribute by defining a getter method that does extra computation (say logging). You can define the getter method (must have a different name than the data attribute) and declare it a property having the same name as what was previously a data attribute. Now all your old code still works but now goes through the extra computation of the getter method. See class "PointWithProperty" below.

    The notion of a property does NOT help in this use case: in your existing class you have defined a getter method: foo.bar() that accesses a "private" data attribute foo._bar . You want to start accessing the attribute using foo.bar . If you change your class to make foo.bar() a property named bar, all your existing calls to foo.bar() now are broken.

    My use case is: I have existing code that accesses a point's attribute x as : point.x. I want to start using QPoint, which accesses a point's attribute x as point.x().

    Suppose I change the definition of QPoint to make x() a property. I really shouldn't be changing a library because branching is bad. Also, other parts of the Qt library probably use QPoint using point.x() notation, and that breaks.

    Suppose I subclass QPoint and make point.x() a property in my subclass, accessible as point.x . Whenever I get a QPoint from Qt I must convert (cast) it to my subclass. Probably it would be just as easy to convert my existing code to use point.x() (which is what I have deciding on: uniformly use method access notation, since Qt is more important to me than other libraries.)

    My question "why isn't QPoint.x a property" is an ignorant question. Even if it were a property, I would not be able to change the getter method in the Qt library to effect new computations. If it were a property, it would help me (anyone who chose data access notation), but would hurt others (anyone who has chosen method access notation.)

    If I had asked "why is QPoint.x() a method instead of a property", I think the answer is: it was an arbitrary choice and the designers couldn't possibly satisfy everyone. If the language does not support the Uniform Access Principle, programmers CAN make the choice between method and data acccess notation, and they WILL make different choices, and there often will be conflicts.

    (Since Ruby supports UAP, if there is a Ruby Qt, I should just go there.)
    @
    class PointWithoutProperty(object):
    def init(self, params):
    self.x = params

    '''
    From Python docs:
    "Data attributes override method attributes with the same name;
    to avoid accidental name conflicts, which may cause hard-to-find bugs in large programs,
    it is wise to use some kind of convention that minimizes the chance of conflicts."

    ("override" above is not quite the usual meaning, it means "permanently hides")

    So the following definition is useless, although there is no error until you try to call it at runtime:
    '''
    def x(self):
    return self.x

    This getter method has a name that doesn't conflict with the data attribute

    def getX(self):
    return self.x

    class PointWithProperty(object):
    def init(self, params):
    self._x = params

    No conflict between method name and data attribute

    def x(self):
    print "attribute x was accessed"
    return self._x

    x = property(x)

    print "\n without Property"
    foo = PointWithoutProperty(1)
    print foo.x

    prints "1"

    print foo.getX()

    prints "1"

    try:
    print foo.x()
    except Exception as inst:
    print type(inst), inst

    prints "TypeError: 'int' object is not callable"

    !!! Even though x() appears as a method definition, it is overridden by the definition of name x as an attribute

    print "\n with Property"
    bar = PointWithProperty(1)
    print bar.x

    prints "attribute x was accessed", "1"

    try:
    print bar.x()
    except Exception as inst:
    print type(inst), inst

    prints "attribute x was accessed", "TypeError: 'int' object is not callable"@



  • If you look where Qt comes from, it's C/C++. C/C+ supports methods and members. A typical thing in C++ (and OOP ) is data hiding, so a class / method using another class should not have access to the used class members directly. To hide this, the typical thing ia adding getter / setter methods.

    I have no idea how that is in python, but in C++, it's exactly this. Otherwise you must make the member üublic what is not what you want.



  • Still, at least at first sight, it would be nice to have such a feature in C++. Not Qt's fault that properties are not implemented this way though.

    I mean, wouldn't it be cool to have this work:

    @QPoint p;
    p.x = 42;
    p.y = -p.x;
    @
    Which would call void QPoint::setX(int) and int QPoint::x() in the background automatically? Perhaps C++ 2019...



  • Yay! That would be really cool - having the advantages of getters and setters (like sanity checks) together with the nice short notion of plain old member attributes.



  • I think my earlier link to wiki discussed how properties can be simulated in C++.

    I'm still wondering whether PySide has not made a design error in their QPoint implementation. Its more Pythonic to make data attributes public (the philosophy is, let the programmer do what they want, even if they get in trouble) without hiding them behind getter/setters. If the developers of PySide later need to intercede, they can use properties to make it still look like a data attribute, but use their defined getter/setter doing whatever intercession they need. But its possible that what the PySide developers can do is constrained.

    Re: "Qt’s design principles to (NOT) expose otherwise private implementation details as public attributes". In C++? Do those principles necessarily carry over to PySide?

    After all, a point IS data, two numbers usually called x and y. In other words, that seems to be a rather fundamental "property" of a point. Why obscure that with getter and setters?

    I don't mean to complain too much, I really appreciate the beauty of Qt and PySide.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.