I have some code that I am using to convert arbitrary QObject subclasses to JSON. I able to convert them if they are pointers to a subclass, but am curious whether it is possible to convert instances (provided the subclass implements a copy constructor). Is there some crazy way to use something like templates or the type information provided by QMetaType to copy an instance of a QObject subclass without knowing what it is? The ToJson code is in a class that has no knowledge of the subclass.
I think it might be possible with QMetaType::create or something similar but I haven't been able to figure out how to actually copy the properties of the subclass instance.
Here's my code for converting:
QJsonValue ToJson(QVariant value){
switch(value.type()){
case QVariant::Int:
case QVariant::Double:
return value.toDouble();
////Other cases, etc...
case QVariant::UserType:
QObject* obj_ptr = qvariant_cast<QObject*>(value);
if(obj_ptr) // value was originally a pointer to a QObject, works correctly
return ToJson(obj_ptr);
else { // value was orginally an instance of a QObject subclass
std::string t = value.typeName(); //returns "MyQObject"
int id = QMetaType::type(t.c_str()); //returns the id of the derived class
void* v = QMetaType::create(id, &value); //passing &value does nothing
obj_ptr = static_cast<QObject*>(v);
return ToJson(obj_ptr); //works, but resulting fields are all default
}
}
}
QJsonObject ToJson(QObject* o){
QJsonObject obj;
auto mo = o->metaObject();
for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
QVariant value = o->property(mo->property(i).name());
obj[mo->property(i).name()] = ToJson(value);
}
return obj;
}
Sample code use case:
qRegisterMetaType<MyQObject>();
MyQObject obj;
obj.db = 11.1;
QVariant test1 = QVariant::fromValue(obj);
QVariant test2 = QVariant::fromValue(&obj);
QJsonValue v1 = ToJson(test1); // default constructed values
QJsonValue v2 = ToJson(test2); // db = 11.1
Sample QObject subclass:
class MyQObject : public QObject {
Q_OBJECT
Q_PROPERTY(double DB MEMBER db)
Q_PROPERTY(int I MEMBER i)
public:
MyQObject();
MyQObject(const MyQObject& other) : QObject() {
i = other.i;
db = other.db;
}
int i = 50;
double db = 1.5;
};
Q_DECLARE_METATYPE(MyQObject)
Is there any way to handle the case illustrated by test1 above?
Long-story-short: nope. There is no way to store QObjects by value in containers or QVariant.
Qt forbids the copy of QObjects and all inheriting classes. The mandatory the Q_OBJECT macro will disable any copy constructor also in newly defined classes.
The copy constructor that you are defining in the MyObject class is missing the base class constructor call. If QObject had a copy constructor it would be something like this:
MyQObject(const MyQObject& other) :
QObject(other) // this will NEVER compile
{
i = other.i;
db = other.db;
}
Probably, the compiler is giving you a warning, but allows you to have such a constructor, even if it will result in undefined behavior or slicing an instance of MyObject every time it is passed by value.
Furthermore, the Qt docs states the following:
The values stored in the various containers can be of any assignable
data type. To qualify, a type must provide a default constructor, a
copy constructor, and an assignment operator. This covers most data
types you are likely to want to store in a container, including basic
types such as int and double, pointer types, and Qt data types such as
QString, QDate, and QTime, but it doesn't cover QObject or any QObject
subclass (QWidget, QDialog, QTimer, etc.).
So you can't store QObject and derived classes inside a Qt container unless you store them as pointers, as copy of QObjects is disabled by design.
Furthermore, if you want to exploit polymorphic behavior you must use pointers, even if there is no explicit need to cast to derived classes in your code, as far as I can see. If you really need to resort to casting in some place, you could consider making your ToJson a template function.
There is a solution, but use caution as it is only reasonable/applicable in the following scenario:
Classes in question are primarily data storage classes
The classes in question would be entirely copy-able if they didn't inherit from QObject
Most importantly, the ONLY reason you have the class inherit from QObject is so that it can have meta properties.
If your code uses the class as a QObject for any reason other than to get meta information, you are almost certainly using it incorrectly if you are trying to store it by value (as explained by G. Giordano in their answer).
Misuse considerations aside, in order to JSON-ify a QVariant that stores a QObject subclass by value, you can use the QMetaType::create method and pass it the user type id and yourQVariant.constData().
Example:
MyQObject obj;
obj.db = 11.1;
QVariant value = QVariant::fromValue(obj);
std::string t = value.typeName();
int id = QMetaType::type(t.c_str());
void* v = QMetaType::create(id, value.constData());
obj_ptr = static_cast<QObject*>(v);
QJsonValue json = ToJson(obj_ptr); //json contains db = 11.1
Related
I'm starting my journey in D from C++. In C++ passing by reference or value is quite explicit, but in D it seems to vary between structs and classes.
My question is how can I force a return by reference?
I have a simple XmlNode class for building Xml trees (which is a lift from my C++ code):
import std.stdio;
struct XmlNode
{
string _name;
string _data;
XmlNode[] _children;
this(string name, string data="")
{
_name = name;
_data = data;
}
//Trying to return a reference to the added Node
ref XmlNode addChild(string name,string data = "")
{
_children ~= XmlNode(name,data);
return _children[$-1];
}
string toString(bool bPlain = true, string indent = "")
{
//Omitted for brevity
}
}
And here is the testing code:
int main()
{
auto root = XmlNode("root");
//Chained call
root.addChild("Level 1").addChild("Level 2","42");
//Call in two parts
auto n = root.addChild("Level 1");
n.addChild("Level 2","101"); //n seems to be a copy not a reference
//Chained call
root.addChild("Level 1").addChild("Level 2","999");
writeln(root.toString(false));
return 0;
}
which gives the following output:
root
Level 1
Level 2
42
Level 1
Level 1
Level 2
999
As you can see the 'chained' use of addChild() performs as hoped. But if I try to break it up into two separate calls, only the first has an effect, and the second seems to operate on a copy of the first, not a reference. I optimistically added a ref qualifier to the addChild() signature, but that doesn't seem to help.
As ever, I'd be grateful for any advice (using DMD / Visual D / Visual Studio / Windows 10).
auto n = root.addChild("Level 1");
Here, though addChild returns a reference, it is assigned to a variable, and thus dereferenced and copied. Instead, you probably want:
auto n = &root.addChild("Level 1");
Note that D does not have reference variables, like in C++. Variables can be only pointers (though it's possible to write a wrapper template with reference-like semantics).
Also note that in the current design of XmlNode, the returned reference will only be valid until the next time _children is modified (as that may cause a reallocation and thus move the contents to another address, making any extant references outdated). It is a common footgun, which could be avoided by storing references of XmlNode (or making it a reference type i.e. a class), at the cost of extra dereferences and allocations.
Can anyone give me a list of languages where class immutability can be compiler enforced and tested easily ?
I need to be able to do something like:
class immutable Person {
private String name = "Jhon"; // lets say the String is mutable
public Person(String name) {
this.name = name; // ok
}
public void setName(String newName) {
this.name = newName; // does not compile
}
public void getName() {
return this.name; //returns reference through which name can't be mutated
}
private void testImmutability() {
getName().setFirstChar('a'); // does not compile
}
}
EDIT:
For a little more clarification, see here.
Functional programming languages like OCAML, Haskell, and Erlang.
F# and Scala both have the ability to created compiler-enforced immutable types (i.e. classes).
The following shows the basics in F#...
// using records is the easiest approach (but there are others)
type Person = { Name:string; Age:int; }
let p = { Person.Name="Paul";Age=31; }
// the next line throws a compiler error
p.Name <- "Paulmichael"
Here's the equivalent Scala. Note that you can still make mutable objects by using var instead of val.
class Person(val name: String, val age: Int)
val p = new Person("Paul", 31)
// the next line throws a compiler error
p.name = "Paulmichael"
Joe-E
From the language spec
3.4 Immutable Types
A type T is immutable if and only if it implements
the marker interface org.joe_e.Immutable according to the overlay
type system. The (empty) org.joe_e.Immutable interface must be provided
by the Joe-E implementation. The
intuition behind an immutable object
is that such an object cannot be
changed (mutated) in any observable
way, nor can any objects reachable by
following the elds of the immutable
object. The contents of an immutable
objects' elds and any objects
reachable from an immutable object
must not change once the object is
constructed. With the exception of
library classes explicitly deemed to
implement Immutable, an immutable
class must satisfy additional
linguistic restrictions enforced by
the verier (x4.4) to ensure this
property. Library classes that cannot
be automatically verified and are
deemed immutable must be carefully
manually veried to expose no
possibility for modication of their
contents. Note that immutability does
not place any restrictions on any
local variables dened within the
immutable class. It also says nothing
about the mutability of the arguments
passed to methods. It only applies to
the values stored in and objects
reachable from the immutable class's
elds
It also introduces useful notions of powerless, and selfless types.
The D (version D2) programming language has immutability. It has OOP, but immutability is rather a concept from functional pl. There it's called purity.
Is there any way for me to define implicit or explicit type conversions in ActionScript?
For instance, I want to define a conversion such that Array can cast into MyClass implicitly. If not, an explicit cast would be useful. I know I can always pass it into my constructor, but I am dealing with semantics here, and I am most interested in a conversion solution if it exists.
Type casting in ActionScript 3
Object(instanceOfOtherObject);
Works based on the valueOf property of the given class (if defined). Therefore, you can define your class MyClass as such:
package {
public class MyClass {
private var myArray:Array;
public function MyClass(inputArray:Array = null) {
myArray = (inputArray ? inputArray : new Array());
}
public function valueOf():Array {
return myArray;
}
}
}
Then you will be able to perform this typecasting:
var mc:myClass = new MyClass();
var arr:Array = Array(myClass);
To my knowledge, the reverse is not an option because the valueOf function of Array does not return an object of type MyClass. There is nothing stopping you from creating a CastableArray that extends and overrides the valueOf function of Array to make it return an instance of MyClass using the constructor I defined above, though you may run into other issues with other fundamental language components that expect an Array to return an Array in its valueOf property (comparison of objects comes to mind).
I have not done any particular testing with this next suggestion, but if MyClass extends from Array and does not define a valueOf function, it may still be possible to do the type conversion depending on the constructor of MyClass and what Flash does in circumstances when valueOf is not defined.
Is there a way to define an enum in AS3 in a way we do it in other languages? I can define constants with defined values like that:
private const CONST_1:int = 0;
private const CONST_2:int = 1;
private const CONST_3:int = 2;
and so on. If I want to insert some other constant between 3 these I need to move all values like that:
private const CONST_1:int = 0;
private const CONST_2:int = 1;
private const CONST_2A:int = 2;
private const CONST_3:int = 3;
while in other language I would end up with only adding a new member to enum closure like that:
enum {
CONST_1 = 0,
CONST_2,
CONST_2A,
CONST_3
} MyConstEnum;
Does AS3 has something similar?
Thanks
No AS3 doesn't have enum, you have to code them yourself. You can simulate them for example by a class if you want safer type checking.
public static var NUM_ENUM_VALUES:int = 0;
public static const EV_MONDAY:int = NUM_ENUM_VALUES++;
public static const EV_TUESDAY:int = NUM_ENUM_VALUES++;
public static const EV_WEDNESDAY:int = NUM_ENUM_VALUES++;
public static const EV_THURSDAY:int = NUM_ENUM_VALUES++;
You can take a look at the variety of variable types supported by the ActionScript Virtual Machine. Variable types are annotated by traits, the variety of which can be found in the specification, table 4.8.1:
4.8.1 Summary of trait types
The following table summarizes the trait types.
Type Value
Trait_Slot 0
Trait_Method 1
Trait_Getter 2
Trait_Setter 3
Trait_Class 4
Trait_Function 5
Trait_Const 6
There is no Trait_Enum and note that under Trait_Const description, only constants from the constant pool are allowed, so that would be:
signed integers
unsigned integers
doubles
strings
type names and vector types
Enums could be made of signed or unsigned integers, for example, but the virtual machine would not perform any type-safety checking of the operations which used those types. (E.g., the getlocal or coerce opcodes used would be getlocal_i and coerce_i, respectively.)
The ABC format doesn't have any built-in provision for enum types that I know of.
Using an object type for each enum value could work, especially if the compiler emits coerce instructions for that type prior to uses of getlocal and otherwise doesn't use the object other than in istype and astype variants. For example, calling setproperty or getproperty on the object would be slower than using an integer -- especially if that property is bound to a getter or setter method.
There are replacement styles which have been linked in other answers. To evaluate the runtime performance impact of these styles, you can uses swfdump -D from the swftoools open-source Flash tools collection.
I've been spending some of my spare time working a set of collections for ActionScript 3 but I've hit a pretty serious roadblock thanks for the way ActionScript 3 handles equality checks inside Dictionary Objects.
When you compare a key in a dictionary, ActionScript uses the === operator to perform the comparison, this has a bit of a nasty side effect whereby only references to the same instance will resolve true and not objects of equality. Here's what I mean:
const jonny1 : Person = new Person("jonny", 26);
const jonny2 : Person = new Person("jonny", 26);
const table : Dictionary = new Dictionary();
table[jonny1] = "That's me";
trace(table[jonny1]) // traces: "That's me"
trace(table[jonny2]) // traces: undefined.
The way I am attempting to combat this is to provide an Equalizer interface which looks like this:
public interface Equalizer
{
function equals(object : Object) : Boolean;
}
This allows to to perform an instanceOf-esq. check whenever I need to perform an equality operation inside my collections (falling back on the === operator when the object doesn't implement Equalizer); however, this doesn't get around the fact that my underlying datastructure (the Dictionary Object) has no knowledge of this.
The way I am currently working around the issue is by iterating through all the keys in the dictionary and performing the equality check whenever I perform a containsKey() or get() operation - however, this pretty much defeats the entire point of a hashmap (cheap lookup operations).
If I am unable to continue using a Dictionary instance as the backing for map, how would I go about creating the hashes for unique object instances passed in as keys so I can still maintain equality?
How about you compute a hash code for your objects when you insert them, and then look them up by the hash code in your backing dictionary? The hashcode should compare === just fine. Of course, that would require you to have a Hashable interface for your object types instead of your Equalizer interface, so it isn't much less work than you are already doing, but you do get the cheap lookups.
How about rather doing this:
public interface Hashable {
function hash():String;
}
personally, I ask myself, why you want to do this ... hashing objects to obtain keys makes little sense if they are mutable ...
also, you might consider using a different approach, as for example this factory:
package {
public class Person {
/**
* don't use this!
* #private
*/
public function Person(name:String, age:int) {
if (!instantiationAllowed)
throw new Error("use Person.getPerson instead of constructor");
//...
}
private static var instantiationAllowed:Boolean = false;
private static var map:Object = {};
private static function create(name:String, age:int):Person {
instantiationAllowed = true;
var ret:Person = new Person(name, age);
instantiationAllowed = false;
}
public static function getPerson(name:String, age:int):Person {
var ageMap:Array = map[name];
if (ageMap == null) {
map[name] = ageMap = [];
return ageMap[age] = Person.create(name, age);
}
if (ageMap.hasOwnProperty(age))
return ageMap[age];
return ageMap[age] = Person.create(name, age);
}
}
}
it ensures, there's only one person with a given name and age (if that makes any sense) ...
Old thread I know, but still worth posting.
const jonny1 : Person = new Person("jonny", 26); const jonny2 : Person = new Person("jonny", 26);
is creating two completely different objects that will not compare using ==, guess I don't see why it's any more of a road block because of as3
The problem with AS3/JavaScript/EcmaScript is not that they create two different, equivalent objects.
The problem is that they cannot equate those two equivalent objects--only identity works, since there is no equals or hashCode methods that can be overriden with class-specific comparison logic.
For Map implementations such as dynamic Object or Dictionary, this means that you have to either use Strings or references as keys: you cannot recover objects from a map using different but equivalent objects.
To work around that problem, people either resort to strict toString implementations (for Object maps) which is undesirable, or to instance control for Dictionaries, as in #back2dos example, which introduces different problems (Also, note that #back2dos solution does not really guarantee unique Person instances since there is a time window during which asynchronous threads will be allowed to instantiate new Persons).
#A.Levy's solution is good except that in general, hashCodes are not strictly required to issue unique values (they are meant to map entries to buckets allowing for fast lookups, wherein fine-grained differentiation is done through equals method).
You need both a hashCode and an equals method, e.g.
public interface IEquable
{
function equals(object : Object) : Boolean;
function hash():String;
}
In any programming language,
const jonny1 : Person = new Person("jonny", 26);
const jonny2 : Person = new Person("jonny", 26);
is creating two completely different objects that will not compare using ==, guess I don't see why it's any more of a road block because of as3