Question about Objects vs. Properties

Can someone please point me to a reference where this is better explained?

I understand that tags as created with Ignition are Objects that have properties associated with them. For example, if I want to see the LastChange property associated with a tag, I would in scripting put something like:

tagslastchange = system.tag.read(‘mytag.LastChange’)

However, if I simply try to print tagslastchange to the console I get something like: [Mon Oct 21 07:27:50 HST 2019, Good, Mon Oct 21 08:48:35 HST 2019]

To properly derive the desired information I wanted (the last time the tag changed) I need to further filter by typing something like print tagslastchange.value.

This is where I’m confused. Is LastChange just a property of it’s tag or a “sub-Object” with it’s own properties? Can someone point me to documentation where this is explained? Also what other tag properties have this feature where they appear to be “sub-Objects”?

Thanks!!

when you use system.tag.read() it returns a qualified tag value. If all you want is the value in the tag you need to put .value at the end so in your case

tagslastchange = system.tag.read(‘mytag.LastChange’).value

Your other options from the read is .quality and .timestamp. I believe .timestamp would also give you your last change value so you could do:

tagslastchange = system.tag.read(‘mytag’).timestamp

I should of also posted the link to system.tag.read(). This is from 7.9. I’m not sure what version your using. But for the last part of your question. The LastChange is a property of the tag but when you put it in the tag read it becomes the object that your pulling and still has to be returned as a qualified value. This is why you need to add the extra piece of either .value, .quality, or .timestamp to any tag your reading with a script to pull the part of the qualified value you want out of it.

As stated by @bpreston, system.tag.read returns an object of class BasicQualifiedValue. This class object has its own set of methods and properties, some of which are value, timestamp, and quality. You can check what class type an object is by using the type function. E.g. Type(tag). You can look at the class definitions here: http://files.inductiveautomation.com/sdk/javadoc/ignition79/795/index.html

What I still don’t really understand, is how you can write tag.value to get the value, without having to call tag.getValue() as you can see in the Java doc definition of the QualifiedValue interface… I’m still a baby to Java

qv.value working isn’t a Java thing - it’s actually a bit of Jython “magic”.

Lots of things in Java conform to the ‘javabeans’ style - classes with private fields, but public getter and setter methods. This is very verbose, and “idiomatic” Python doesn’t use getters/setters (although you can). So, to make working with Java classes more “idiomatic” from Jython, Jython does some pretty magical stuff to turn methods like getSomeProperty()/setSomeProperty() into an attribute someProperty - so <qualified value object>.getValue() is also available as an attribute <qualified value>.value when you’re looking at the class from Jython.

There’s no strong reason to use one or the other - one is more idiomatic Python, but relies on “magical” Jython automatic handling, the other is (much) more verbose and just makes your Python code look like Java code.

4 Likes

Yeah, don’t do that. /:
Auto-conversion of java getters and setters to python properties is a critical feature, IMNSHO. Jython would be a much more miserable place without it.

1 Like

Let me elaborate:

Jython “wraps” Java objects for use in its interpreter. The standard wrappers basically do this:

  1. Public fields in java become matching properties in Jython. Read-write if the java doesn’t use final.
  2. Public methods in java become matching methods in Jython. When multiple methods share the same name–different argument lists–they are wrapped into the same jython method, and picking the correct one is deferred until called. Which looks at the number of arguments given.
  3. Public methods of the form getAbcdEfgh() (no arguments) will be turned into a readable property named abcdEfgh. Unless a public java field already has that name (iirc). If the java return value is boolean, the method isAbcdEfgh() is treated the same. Note the case change in the first letter of the property name.
  4. Public methods of the form setAbcdEfgh(SomeType v) (just the one argument) will be turned into a writeable property named abcdEfgh, combining with the getter above if present. The SomeType in the set form must match the return type of the get form. This feature allows you to put the emulated property on the left-hand side of an assignment in jython.

Non-standard wrappers (like the PyComponentWrapper in Vision) can do anything they want, including leaving out features that the standard wrapper would include.

3 Likes

To everyone who responded, THANK YOU for your explanations! I am continually impressed by the power of Ignition… Despite having used this for the past 1-2 years I’m still learning and having the forums available are a wonderful resource. Again, thanks!

1 Like