Is there a way to register types from gobject introspection? - glib

I'm currently experimenting with the gobject-introspection library. One thing I would like to do is to be able to register types (classes in particular) from the information I can obtain. Specifically so I can get a GLib.Type which I can then use to instantiate a class with GLib.Object.new
I have successfully loaded a namespace from a typelib, and I can get information about the classes etc in the namespace, but I am uncertain how to move on from there?
static void main(string[] args){
var rep = GI.Repository.get_default();
rep.require("Gtk", null, 0);
var oinfo = (GI.ObjectInfo)rep.find_by_name("Gtk", "Button");
}
from oinfo i can now easily obtain the name, etc. of the class, I have all the metadata there, as far as I can tell. But suppose I can not reference the type like: typeof(Gtk.Button) or otherwise directly refer to it in the code, how to I register this type with the type system so that I may instantiate it?

Right, so I have solved this myself, after a LOT of tinkering. But after all it turned out not to be so difficult. The most involved way to do this is using a shared library that has just been compiled, so my example will involve that:
First, lets create a shared library containing just one class in one file:
namespace TestLib{
public class TestBase : Object{
private static int counter = 0;
public int count{
get{
return ++counter;
}
}
}
}
This needs to be compiled to a shared library file
valac --library=TestLib -H TestLib-1.0.h --gir=TestLib-1.0.gir TestLib.vala -X -fPIC -X -shared -o TestLib.so
Then use the gir compiler and generate the typelib
g-ir-compiler --shared-library=TestLib TestLib-1.0.gir -o TestLib-1.0.typelib
Then we write the program we want to run:
using GI;
namespace TestRunner{
static int main(string[] args){
var namesp = "TestLib"; //set the name of the namespace we want to load
var rep = Repository.get_default(); //Obtain default repository
rep.require_private(".", namesp, null, 0); //load namespace info from the current folder (this assumes the typelib is here)
var rtinfo = (RegisteredTypeInfo)rep.find_by_name(namesp, "TestBase"); //retrieves the BaseInfo of any type in the "TestLib" namespace called "TestBase" and casts it
var type = rtinfo.get_g_type(); //Calls the get type, registrering the type with the type system, so now it can be used as we wish
var objt = Object.new(type); //object is instantiated, and we can use it
Value val = Value(typeof(int));
objt.get_property("count", ref val);
message(val.get_int().to_string());
objt.get_property("count", ref val);
message(val.get_int().to_string());
message("type is: %s".printf(type.name()));
return 0;
}
}
Then we compile this program: valac TestLib.vapi TestRunner.vala -X TestLib.so -X -I. -o testintro --pkg=gobject-introspection-1.0
And before we run it, we will remember to add this dir to the path, so the program knows where to find the shared library: export LD_LIBRARY_PATH=.
finally we run the new program: ./testintro
And we should see:
** Message: 22:45:18.556: TestRunner.vala:9: Chosen namespace is: TestLib
** Message: 22:45:18.556: TestRunner.vala:24: 1
** Message: 22:45:18.556: TestRunner.vala:28: 2
** Message: 22:45:18.556: TestRunner.vala:30: type is: TestLibTestBase

Related

Dart: how to run static function/code "automatically"?

In Dart (Flutter) I would like to have some static code run without being explicitly invoked.
I tried this:
// File 1
class MyClass {
static int member = 42;
}
int dummy = 42;
and file 2:
// File 2
void main() {
int tmp = MyClass.member;
}
I put a breakpoint on the dummy = 2; line but it seemed to never be invoked.
I also tried:
// File 1
class MyClass {
static int member1 = 42;
static int member2 = SomeOtherClass.someFunc();
}
and file 2:
// File 2
void main() {
int tmp1 = MyClass.member1;
int tmp2 = MyClass.member2;
}
With this, SomeOtherClass.someFunc() was invoked when the int tmp2 = ... line was invoked.
I would like SomeOtherClass.someFunc() to be invoked without explicitly accessing MyClass.member2. I would like it invoked on any of the following triggers:
When the program starts (before main() is called).
OR, when code in a file in which MyClass is imported is invoked for the first time.
Is either of these possible in Dart?
This behavior is intentional and cannot be changed. As jamesdlin also explain, all static variables (class and global) in Dart are lazy evaluated and will first get a value with first attempt to access the value.
This is design is described in the Dart specification followed up with a reason for that design choice:
Static variable declarations with an initializing expression are initializedlazily.
The lazy semantics are given because we do not want a language where one tends to define expensive initialization computations, causing long application startup times. This is especially crucial for Dart, which must support the coding of client applications.
https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf

How to reference static classes in Actionscript

I apologize in advance for the newbiness of this question; I think I'm not grasping the basics of Actionscript but haven't been able to find an answer elsewhere.
What I want is some global constants like one would have in C++. In C++, I would simply have a file where I would #define MAP_HEIGHT 20, or something like that, and they would be globally accessible when I included the file at the top. In Actionscript, I've tried making a static class instead, like so:
package
{
public class Settings {
public const mapx:int = 20;
public function Settings() {}
}
}
But when I try to reference it in my code with colon syntax
var a:int = Settings::mapx;
I get the error "[Fault] exception, information=TypeError: Error #1034: Type Coercion failed: cannot convert Settings$ to Namespace."
I tried dot syntax:
var a:int = Settings.mapx;
and got a different error, "Access of possibly undefined property mapx through a reference with static type Class."
But what I really want is a file of global static variables, like in C++, and can't find a way to do it in Actionscript.
Mark variables, constants, and functions with the static keyword, as in:
package
{
public class MathUtil
{
public static const PI:Number = 3.141592653589;
public static function deg2rad(angle:Number):Number
{
angle = !isNaN(angle) ? (angle) : (0);
return angle * PI / 180;
}
}
}
Then you may use dot notation.
var pi:Number = MathUtil.PI;
var angle:Number = MathUtil.deg2rad(45);
From ActionScript 3.0 Reference for the Adobe Flash Platform: Statements, Keywords & Directives
Usage
class someClassName {
static var varName;
static const kName;
static function methodName() { }
}
You can use static in class definitions only, not in interface
definitions.
Static class members are not inherited. You cannot refer to a static
class member using the name of a subclass, as you can in Java or C++.
You can, however, refer to a static variable or method within a class
or subclass, without using any qualifier. See the example below.
You cannot use the super statement or the this keyword inside a static
method.

Reading static files under a library in Dart?

I am writing a library in Dart and I have static files under the library folder. I want to be able to read those files, but I'm not sure how to retrieve the path to it... there is not __FILE__ or $0 like in some other languages.
Update: It seems that I was not clear enough. Let this help you understand me:
test.dart
import 'foo.dart';
void main() {
print(Foo.getMyPath());
}
foo.dart
library asd;
class Foo {
static Path getMyPath() => new Path('resources/');
}
It gives me the wrong folder location. It gives me the path to test.dart + resources/, but I want the path to foo.dart + resources/.
As mentioned, you can use mirrors. Here's an example using what you wanted to achieve:
test.dart
import 'foo.dart';
void main() {
print(Foo.getMyPath());
}
foo.dart
library asd;
import 'dart:mirrors';
class Foo {
static Path getMyPath() => new Path('${currentMirrorSystem().libraries['asd'].url}/resources/');
}
It should output something like:
/Users/Kai/test/lib/resources/
There will probably be a better way to do this in a future release. I will update the answer when this is the case.
Update: You could also define a private method in the library:
/**
* Returns the path to the root of this library.
*/
_getRootPath() {
var pathString = new Path(currentMirrorSystem().libraries['LIBNAME'].url).directoryPath.toString().replaceFirst('file:///', '');
return pathString;
}
The dart mirrors API (still experimental, and not available on all platforms such as dart2js yet) exposes a url getter on the LibraryMirror. This should give you what you want.
I'm not aware of any other way to get this information on a library.
#import('dart:mirrors');
#import('package:mylib/mylib.dart');
main(){
final urlOfLib = currentMirrorSystem().libraries['myLibraryName'].url;
}
Generally the usual method of accessing resources which are located at a static position with your library is by use using a relative path.
#import('dart:io');
...
var filePath = new Path('resources/cool.txt');
var file = new File.fromPath(filePath);
// And if you really wanted, you can then get the full path
// Note: below is for example only. It is missing various
// integrity checks like error handling.
file.fullPath.then((path_str) {
print(path_str);
});
See addition API information on Path and on File
As an aside.. If you absolutely wanted to get the same type of output as __FILE__ you can do something like the following:
#import('dart:io');
...
var opts = new Options();
var path = new Path(opts.script);
var file = new File.fromPath(path);
file.fullPath().then((path_str) {
print(path_str);
});

Inconsistent error reporting from Dart Editor regarding final fields

Given the following class, Dart Editor (build 5549) gives me some conflicting feedback (per the comments in the constructor body):
class Example {
final int foo;
Example() :
foo = 0
{
foo = 1; // 'cannot assign value to final variable "foo"'
this.foo = 2; // ok
}
}
Even more confusingly, it will happily generate equivalent (working) javascript for both lines. The situation seems to be the same with methods as it is with the constructor; this especially leads me to believe that it was intended to be disallowed in both cases.
The Dart Style Guide suggests using public final fields instead of private fields with public getters. I like this in theory, but non-trivial member construction can't really go into the initializer list.
Am I missing a valid reason for the former to be reported as an error while the latter is not? Or should I be filing a bug right now?
This is surely a bug in the JavaScript generator if you run the following in the Dart VM:
main() {
new Example();
}
class Example {
final int foo;
Example() : foo = 0 {
foo = 1; // this fails in the dart vm
this.foo = 2; // this also fails in the dart vm
}
}
then it refuses to execute both the line foo = 1 and this.foo = 2. This is consistent with the spec which requires (if I read it correctly) that final fields to be final in the constructor body.

Do C++ Templates play nicely with VCL classes?

I'm trying to use C++ Template 'mixins' to create some new VCL components with shared additional functionality. Example...
template <class T> class Mixin : public T
{
private:
typedef T inherited;
// ...additional methods
public:
Mixin(TComponent *owner) : inherited(owner)
{
// .. do stuff here
};
};
Used like this:
class MyLabel : public Mixin<TLabel>
{
....
}
class MyEdit : public Mixin<TEdit>
{
....
}
Now, everything compiles fine, and the mixin stuff seems to work - until I try and save the component to a stream using TStream->WriteComponent, where the inherited properties (eg TLabel.Width/Height/etc.) don't get written. This is even with a 'null' mixin like the one shown above.
My code works fine when just deriving classes directly from TForm, TEdit, etc - and the class is correctly registered with the streaming system.
The quick/simple answer is: no; when dealing with a template, the compiler won't generate the proper descriptors to make streaming working. However, since this has come up before, I peeked under the cover to find out what's missing. And what I found is that it's almost there. So here's a little more information.
Upfront the compiler will never treat a template-based type as a Delphi. For example, do something like this:
void testing()
{
__classid(Mixin<Stdctrls::TLabel>); // Error Here
}
... and you'll see the error
"Error E2242 test.cpp 53: __classid requires Delphi style class type (i.e. class marked __declspec(delphiclass) or derived from System::TObject) in function testing()"
This basically says the compiler does not consider this type/class as compatible with Delphi-classes [i.e. those that derive from TObject]. Internally there's just a flag on the symbol that says whether the type is delphi-compatible or not. And I noticed that I could trick the compiler into marking the type as delphi-style if I forced it to walk up the hierarchy.. which is something it has to do if I create an instance of the object. So, with this hack the error goes away:
void testing()
{
typedef Mixin<Stdctrls::TLabel> __ttype;
std::auto_ptr<__ttype> c2(new __ttype(0));
__classid(Mixin<Stdctrls::TLabel>); // No more errors here
}
But much nicer was actually to use the __declspec(delphiclass) directly on the template, as in:
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
So now that the compiler treats the type as a delphi-style class without hacks, I peeked a little more and found the issue you're probably running into: Delphi classes have the TTypeData.PropCount field - http://docwiki.embarcadero.com/VCL/en/TypInfo.TTypeData - which is a sum of the class' properties, including those of its base classes. Due to the way the various pieces of information are computed, the compiler writes out a '0' for that field when a template is involved:(
You can see this by printing out the PropCount, as in:
#include <Stdctrls.hpp>
#include <cstdio>
#include <memory>
#include <utilcls.h>
class TCppComp : public Classes::TComponent {
int i;
public:
__fastcall TCppComp(TComponent* owner): Classes::TComponent(owner) {};
__published:
__property int AAAA = {read=i, write=i};
};
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
typedef Mixin<TCppComp> TMixinComp;
void showProps(TClass meta) {
PTypeInfo pInfo = PTypeInfo(meta->ClassInfo());
int Count = GetPropList(pInfo, tkAny, NULL);
TAPtr<PPropInfo> List(new PPropInfo[Count]);
std::printf("Class: %s - Total Props:%d\n",
AnsiString(pInfo->Name).c_str(), Count);
GetPropList(pInfo, tkAny, *(reinterpret_cast<PPropList*>(&List)));
for (int i = 0; i < Count; i++) {
AnsiString propName(List[i]->Name);
std::printf("\t%s\n", propName.c_str());
}
}
void test() {
showProps(__classid(TCppComp));
showProps(__classid(TMixinComp));
}
int main() {
test();
return 0;
}
When run the above prints:
Class: TCppComp - Total Props:3
AAAA
Name
Tag
Class: #%Mixin$8TCppComp% - Total Props:0
IOW, Mixin shows up with '0' published properties while its base type has 3:(
I suspect the streaming system relies on this count and that's why inherited properties are not being written out in your setup.
I considered tweaking the generated descriptors at runtime but since we write them to _TEXT it's bound to trigger DEP.
I'll look at the logic that computes the PropCount to see if there's some way to get it to compute the correct number. If time allows, please do open a QC for this: now that I've peek underneath, I believe it would not require much effort to get this working as expected.
Cheers,
Bruneau
PS: In my sample I even had the Mixin publish a property and the compiler generated the correct descriptor for that property; however, the total count was still zero.

Resources