I'm trying to use function pointers in DLang (Pointer to function), but it wont compile. All the code on the web on making function pointers, doesn't work for me. This is my code:
tqvar function(tqlist)[string] procs;
procs["divide"] = รท/// cannot implicitly convert expression (&this.divide) of type tqvar delegate(tqlist args) to tqvar function(tqlist) (QScript)
tqvar divide(tqlist args){
tqvar result;
result.ii = true;
result.d = args.read(0).d/args.read(1).d;
return result;
};
I'm using dmd2, on ubuntu.
divide is apparently a delegate, not a function. You can either use a list of delegates instead (just replace function with delegate) or ensure your function is not a delegate.
For the latter: it looks like divide is a class method, not a plain function. Either make it static or move it outside of the class body.
Related
I have the following scenario (https://run.dlang.io/is/19OOW9):
import std.stdio;
void main(string[] args)
{
inter1 c1 = new foo();
foo c2 = new foo();
writeln("Origin=interface: ", typeof(c1).stringof);
writeln("Origin=class: ", typeof(c2).stringof);
}
interface inter1 {
}
class foo : inter1 {
}
I work with interfaces and have different implementations for them. Now I need to know which concrete implementation is currently being used. So in the example above, I would like to know from c1 that it is an instance of the class foo.
Is this possible in the language D?
I have already tried the possibilities of object (e.g. TypeInfo_Class) and std.traits. Unfortunately without success.
A workaround is, of course, to provide the interface with a suitable meta method (https://run.dlang.io/is/Xnt0TO):
import std.stdio;
void main(string[] args)
{
inter1 c1 = new foo();
foo c2 = new foo();
writeln("Origin=interface: ", c1.strategyName);
writeln("Origin=class: ", c2.strategyName);
}
interface inter1 {
#property string strategyName() const;
}
class foo : inter1 {
#property string strategyName() const {
return "foo";
}
}
However, this is cumbersome and unusual for D. I can well imagine that there is a better implementation of this.
Best regards
Thorsten
It is quite simple actually: first cast to Object, then fetch the typeid, after a null check:
Object o = cast(Object) your_object;
if(o is null) { /* i don't think this ever happens but you should check anyway */ }
writeln(typeid(o)); // will tell the class name
If you want to call a method on a specific class, you can just cast directly to your class, and again, null check it.
The intermediate cast to Object allows the typeid (aka classinfo) to succeed, whereas calling it directly on an interface always returns the typeid of the interface itself. This is because a D interface is defined to be very thin for maximum compatibility with other languages and doesn't automatically assume run time type information is actually present through it. But the cast to Object tells it you are assuming the RTTI is present, and then typeid will pull it.
Note that the typeid data doesn't provide a whole lot of information... it is mostly just what's needed for dynamic cast, comparison, and other features of the language runtime. But one convenience method it has is a class name and toString methods, which is why the writeln succeeds. But if you're looking for more detailed runtime reflection, you'll have to do it with a CT bridge function, or probably better yet, just write your own methods in the interface.
But if all you need is the class name, use that toString. It gives the fully-qualified name, including module name, so instead of foo, you will get like yourmodule.foo. You can just cut that off if you like by slicing at the dot.
I use QtConcurrent::blockingMapped() to execute the function on the list of single arguments on multiple threads. It's really great!
But I'd like to do same thing calling the function that takes more than one argument, i.e:
// prototype:
static void openAndProcess(QString FileName, QImage &image);
And this is my data:
QList<QString> fileList;
QList<QImage> qImageList;
And I would like to execute QtConcurrent::blockingMapped() on my openAndProcess() function using both above QLists...
How should I do it?
Thanks in advance!
Create a POD struct with pointers to the data. This is the only way to do this without reimplementing lots of unfun things in QtConcurrent.
Or, consider using QList<QPair<QString, QImage> >, which is effectively the same thing.
I'm trying to convert an image in my assets folder
"./assets/image1.png"
to type Object. It needs to be Object because that's what the function I'm using it in is expecting.
Any ideas what would be the simplest way to do this?
Do you mean something like :
[Embed(source="assets/logo.jpg")]
private var logo:Class;
private function init(e:Event):void
{
this.displayImage(logo as Object);
}
private function displayImage(img:Object):void
{
//Assuming you have an image control on stage with an instance
//name of "myImage"
myImage.source = img;
}
If the function you are passing the image to is expecting an Object object, you can in pass anything, it won't reject it. That doesn't mean the function will work correctly, though. Any value will be an Object (except for undefined, which will be accepted but coerced to null and maybe some other strange cases).
So, assuming you didn't write the function yourself, do you have any doc that describes what it expects? Or maybe you have the source code for it?. Otherwise, if the only thing you know about what this function expects is that the parameter must be of type Object... you're in trouble, I think.
Why don't you create a new Object containing the information about the image... including the path.
var obj:Object = new Object();
obj.path = "/assets/image.jpg";
obj.height = 32;
obj.width = 32;
trace(obj.path);
// or, if Flex
Alert.show(obj.path);
And then just pass the new Object into the function and access it like I have above.
I'm looking for method to create Vector and push some values without defining variable Vector. For example:
I have function:
public function bla(data:Vector.<Object>):void { ... }
this function expects Vector as parameter. I can pass parameters this way
var newVector:Vector.<Object> = new Vector.<Object>();
newVector.push("bla1");
newVector.push("bla2");
bla(newVector);
Can I do it in one line in Flex? I'm looking for something like:
bla(new Vector.<Object>().push("bla1").push("bla2"));
I've also tried this:
bla(function():Vector.<Object> { var result:Vector.<Object> = new Vector.<Object>(2, true); result.push("bla1"); result.push("bla2"); return result; });
But it complains:
1067: Implicit coercion of a value of type Function to an unrelated type __AS3__.vec:Vector.<Object>...
Thanks
You can't chain Vector.push() calls as they return uint's -- the new vector length.
The coercion problem, on the other hand, happens because you are passing a function to the bla function, which expects a Vector.<Object>.
You could fix that easily:
bla((function():Vector.<Object> {
var result:Vector.<Object> = new Vector.<Object>(2, true);
result.push("bla1");
result.push("bla2");
return result; })()
);
However, there's already a top level function in AS3 that helps you creating vectors.
The Vector() function expects either an Array or a Vector and returns a Vector. So, for example, you could use:
bla(Vector.<Object>(['bla1', 'bla2']));
Visit the AS3 Reference for more info.
EDIT: I forgot to mention that the fix on the function approach was simply adding a () to it, meaning we actually called the anonymous function and passed it's return to the bla function.
Just want to mention push takes multiple arguments, and each one is pushed onto the stack sequentially:
function getVector():Vector.<String>
{
var newVector:Vector.<String> = new Vector.<String>();
newVector.push("blah1","blah2","blah3","blah4");
return newVector;
}
I'm not really sure why you'd need to do it one line. You could always write a wrapper class if you happen to do this often. The wrapper class could have a push method that returns a reference to the original object so you can use the first method you wanted.
You could also write a helper function which created a new vector and added the elements to the vector and then returned the vector.
Is there a particular need for wanting this on one line?
You are not able to do this:
bla(new Vector.<Object>().push("bla1").push("bla2"));
because the "push" method returns the length of the Vector. So what this means is that you are trying to push the String "bla2" onto the int 1. This won't work!
And your next example is passing a function to the bla method, not calling that function and passing the returned Vector.
Also you are saying the Vector type is "Object" but you are passing in Strings. You should do this:
Vector.<String>
You could do something like this:
function getVector():Vector.<String>
{
var newVector:Vector.<String> = new Vector.<String>();
newVector.push("bla1");
newVector.push("bla2");
return newVector;
}
bla( getVector() );
I have a "format" method that works in a similar manner to the C# String.Format method, with the following signature:
In a class named StringTools:
/**
* Formats a string, based on C# String.Format method.
* #param raw A string with numbered tokens, such as "{0}, {1}"
* #param rest Values that replace the numbered tokens in raw.
*/
public static function format(raw:String, ...rest:*):String;
StringTools.format("{0}, {1}", "Hello", "World") returns the string "Hello, World" as expected. Now, I'm trying to get my logging class to use this method, but I'm having trouble passing the optional variables through. The signature of the method in the logging class is:
public static function infof(raw:String, ...rest:*):String;
If I pass "rest" directly into StringTools.format(raw, rest), it's passed in as an array, and not as a series of parameters, so if I call it liks this: infof("{0}, {1}", "Hello", "World"), I get the string "Hello,World, {1}", since it replaces the first token with the entire array of values.
I also tried constructing an arguments array, and calling the method like this:
var collectArgs:Array = [raw];
for (var i:Number = 0; i < rest.length; i++)
{
collectArgs.push(rest[i]);
}
var callFunction:Function = StringTools.format.call;
trace(callFunction.apply(null, collectArgs));
However, this traces "World,6". So, it looks like the parameters are shifted. So, I tried initializing collectArgs as [null, raw], and I get "Hello World,6. The number is {1}" again.
Am I doing something wrong? What is the correct way to pass optional parameters from one method that expects optional parameters to another method that expects optional parameters?
Thanks!
I think you are on the right lines using apply. This seems to do illustrate the behaviour you want:
static function f1(raw:String, ...rest:*):void
{
trace("f1: "+raw+" "+rest);
rest.unshift(raw);
f2.apply(null, rest);
}
static function f2(raw:String, ...rest:*):void
{
trace("f2: "+raw+" "+rest);
}
function passSomeArguments():void
{
f1("A",1,2,3);
}
EDIT: You need to pass 'null' as the 1st parameter to apply because the first parameter is what is considered to be 'this' when the function is called. Since the functions are static (and in any case have no dependency on 'this') you can pass null, but you must pass something.
You could also do something like this (of course this is not best implementation for the string formatting):
public static function format(raw:String, ...rest:*):String {
if (rest[0] is Array && rest.length == 1) {
rest = rest[0];
}
var r:RegExp = /(\{\d+\})/g;
var matches:Array = raw.match(r);
for (var i:Number = 0; i < rest.length; i++) {
raw = raw.replace(matches[i], rest[i]);
}
return raw;
}
Then your infof function would just look like this:
public static function infof(raw:String, ...rest:*):void {
var formatted = StringTools.format(raw, rest);
}
As mentioned in my comment, if you remove the call method from the end of you callFunction setter, then you do not need to supply null as the first argument. See http://livedocs.adobe.com/ to understand what the call method actually does, and what the first parameter is for.
As #stephen mentioned, it is a lot simpler to unshift your raw var onto the rest array, rather than building up a new one.
Actually, just found that it's my problem. It should work fine using the argument collection method described, as long as the first element in the arguments array is null. I'm not sure why null is necessary, but it works fine this way.