Pybind11 Virtual Child Class Method not being called during recursion, Base Called instead - pybind11

I have a simple test case for polymorphism that isn't working quite right.. I have two C++ classes, Client and Dispatcher. The dispatcher has a method called "Dispatch" that takes a Client* as an input and calls the clients virtual ProcessEvent() method. I've made both of these classes available to python using the code below. I've derived from the Client class as the python class SomeClient and overridden its ProcessEvent function. When I call "Dispatch" from anywhere EXCEPT inside the SomeClient:: ProcessEvent method, everything works as expected, I get a report from the child class. But when I call Dispatch from within SomeClient:: ProcessEvent, the base classes ProcessEvent is called. Any ideas what could be going wrong here? I expect to get an infinite recursion that results in SomeClient:: ProcessEvent being called forever.
C++:
#include <iostream>
#include "pybind11/pybind11.h"
namespace py = pybind11;
class Dispatcher;
class Client
{
public:
Client(Dispatcher* disp): PtrD(disp)
{
std::cout << "In Client::Client\n";
}
virtual ~Client(){};
virtual void ProcessEvent()
{
std::cout << "THIS SHOULDN'T HAPPEN --In Client::ProcessEvent\n";
}
Dispatcher* PtrD;
};
class Dispatcher
{
public:
Dispatcher()
{
std::cout << "In Dispatcher::Dispatcher\n";
}
virtual ~Dispatcher(){};
void Dispatch(Client* client)
{
std::cout << "Dispatcher::Dispatch called by " << client << std::endl;
client->ProcessEvent();
}
};
class DispatcherTrampoline : public Dispatcher
{
public:
using Dispatcher::Dispatcher;
};
class ClientTrampoline : public Client
{
public:
using Client::Client;
void ProcessEvent() override
{
PYBIND11_OVERLOAD(void,Client,ProcessEvent,);
}
};
PYBIND11_MODULE(libTestCase,mod)
{
py::class_<Client,ClientTrampoline> cli(mod,"Client");
cli.def(py::init<Dispatcher* >());
cli.def("ProcessEvent",&Client::ProcessEvent);
cli.def_readwrite("PtrD",&Client::PtrD);
py::class_<Dispatcher,DispatcherTrampoline> dsp(mod,"Dispatcher");
dsp.def(py::init< >());
dsp.def("Dispatch",&Dispatcher::Dispatch);
}
Python Test:
from build.libTestCase import Client,Dispatcher
class SomeClient(Client):
def __init__(self,d):
print("In SomeClient::__init__")
super().__init__(d);
def ProcessEvent(self):
print("in SomeClient::ProcessEvent,about to call self.ProcessEvent")
self.PtrD.Dispatch(self);
if __name__ == "__main__":
dd = Dispatcher()
cl = SomeClient(dd)
dd.Dispatch(cl)
TERMINAL OUTPUT:
In Dispatcher::Dispatcher
In SomeClient::__init__
In Client::Client
Dispatcher::Dispatch called by 0x20bb270
in SomeClient::ProcessEvent,about to call self.ProcessEvent
Dispatcher::Dispatch called by 0x20bb270
THIS SHOULDN'T HAPPEN --In Client::ProcessEvent

Related

How to write C# implementation for a Q# operation with intrinsic body?

I have created a library in C# to be used in Q# programs. The library has two scripts, a C# class library called "Class1.cs" and a matching Q# script called "Util.qs", I share the code snippet of each here:
Class1.cs:
using System;
using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
namespace MyLibrary {
class Class1 : QuantumSimulator {
static void Method_1 (string str) { ... }
.
.
.
}
}
Util.qs:
namespace MyLibrary {
operation Op_1 (str : String) : Unit { body intrinsic; }
}
There is another Q# program in a different namespace that uses the namespace "MyLibrary" so after adding reference, in this Q# program I have:
namespace QSharp
{
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Intrinsic;
open MyLibrary;
operation TestMyLibrary() : Unit {
Op_1("some string");
}
}
When I execute "dotnet run" in the terminal I receive this message:
Unhandled Exception: System.AggregateException: One or more errors
occurred. (Cannot create an instance of MyLibrary.Op_1 because it is
an abstract class.) ---> System.MemberAccessException: Cannot create
an instance of MyLibrary.Op_1 because it is an abstract class.
How can I fix it?
Thanks.
UPDATE:
Following Mariia' answer and also checking Quantum.Kata.Utils, I changed my code as following:
So, I changed Class1 script to:
using System;
using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
namespace MyLibrary {
class Class1 : QuantumSimulator {
private string classString = "";
public Class1() { }
public class Op_1_Impl : Op_1{
string cl_1;
public Op_1_Impl (Class1 c) : base (c) {
cl_1 = c.classString;
}
public override Func<string, QVoid> Body => (__in) => {
return cl1;
};
}
}
Now the error messages are:
error CS0029: Cannot implicitly convert type 'string' to 'Microsoft.Quantum.Simulation.Core.QVoid'
error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types
in the block are not implicitly convertible to the delegate return type
Having checked Quantum.Kata.Utils, I realised I need to create a field and a constructor for Class1 which is a base class and also I should override Func<string, QVoid> as the Op_1 parameter is string type. But I am not sure if each of these steps individually is done properly?
Second Update:
I have changed the previous c# code in first update to the following one:
using System;
using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
namespace MyLibrary {
class Class1 : QuantumSimulator {
public Class1() { }
public class Op_1_Impl : Op_1{
Class1 cl_1;
public Op_1_Impl (Class1 c) : base (c) {
cl_1 = c;
}
public override Func<string, QVoid> Body => (__in) => {
return QVoid.Instance;
};
}
}
Now the error message is the same as the very first one:
Unhandled Exception: System.AggregateException: One or more errors
occurred. (Cannot create an instance of MyLibrary.Op_1 because it is
an abstract class.) ---> System.MemberAccessException: Cannot create
an instance of MyLibrary.Op_1 because it is an abstract class.
And also in this new code shouldn't the constructor public Class1() { } have a parameter? if so what datatype?
In your code, there is nothing connecting the Q# operation Op_1 and the C# code that you intend to implement it in Method_1.
Q# operations are compiled into classes. To define a C# implementation for a Q# operation with the intrinsic body, you have to define a class that implements the abstract class into which your Q# operation gets compiled; so you would have something like public class Op_1_Impl : Op_1.
Getting all the piping right can be a bit tricky (it's a hack, after all!) I would recommend looking at the operation GetOracleCallsCount and its C# implementation to see the exact pieces that have to be in place for it to work.
For the updated question, the signature of your method says that it takes string as an input and returns nothing (QVoid), but the implementation tries to return a string cl_1, so you get a Cannot implicitly convert type 'string' to 'Microsoft.Quantum.Simulation.Core.QVoid'.
To provide a custom C# emulation for your Op_1 Q# operation, you'll need to replace your Class1.cs with something like this:
using System;
using Microsoft.Quantum.Simulation.Core;
namespace MyLibrary
{
public partial class Op_1
{
public class Native : Op_1
{
public Native(IOperationFactory m) : base(m) { }
public override Func<String, QVoid> Body => (str) =>
{
// put your implementation here.
Console.WriteLine(str);
return QVoid.Instance;
};
}
}
}
You can then run the Test1Library using the QuantumSimulator.
That being said, as Mariia said, this is kind of hacky, undocumented functionality that might change in the future, may I ask why you need this?

HoloLens Callbacks with Native Library

My goal is to call methods, which are implemented in the Unity Code, from my UWP DLL. (So I can use them in my HoloLens Project)
I tried this with a bigger project but failed. Therefore I wrote a simple example to make it easier to find the mistake and exclude other influences.
But still, I get the same error.
My Working Environment:
64-bit Computer with OS Windows 10
Micsrosoft Visual Studio Community
2015 Version 14.0.25431.01 Update 3
HoloLens Emulator 10.0.14393.0
Unity 5.5.0f3 Personal (64 bit)
Creating the UWP DLL:
To approach this I created a C++ DLL(Windows Universal) in Visual Studio 2015 as followed:
New Project > Visual C++ > Windows > Universal > DLL(Universal Windows)
After the project was auto generated I added my code.
So the code looks like this:
Native Library Code:
SimpleProjectDLL.cpp:
#include "pch.h"
#define DLL_EXPORT __declspec(dllexport)
typedef void(*CB_V)();
typedef void(*CB_V_VI)(const char * a, int b);
CB_V_VI cb_native_log;
CB_V cb_call;
void log()
{
// this method makes problems !
cb_native_log("Call for callback", 1);
}
extern "C" {
DLL_EXPORT void initInterfaceCallbacks(
CB_V_VI native_log,
CB_V call
) {
cb_native_log = native_log;
cb_call = call;
}
DLL_EXPORT void callSmth()
{
cb_call();
}
DLL_EXPORT int getSomeInt()
{
return 42;
}
DLL_EXPORT void initCallback()
{
log();
}
}
SimpleProjectDLL.h is prepearing the delegates:
SimpleProjectDLL.h:
#pragma once
#include <cstdint>
#define DLL_EXPORT __declspec(dllexport)
extern "C"
{
typedef void(*CB_V)();
typedef void(*CB_V_VI)(const char * a, int b);
}
I did not make any changes to the auto generated files dllmain.cpp, pch.cpp, pch.h or targetver.h.
Finally I build the project for "Release" mode and architecture "x86" to generate the DLL-file.
Location of the DLL-file is now: project-root-folder/Release/SimpleProject/SimpleProjectDLL.dll.
---------------------
Next step I created a new Unity Project added the HoloLens-Toolkit and made sure that the new project is running fine on the emulator.
Unity Project Code:
After that I added the SimpleProjectDLL.dll in the Asset-Folder and implemented the following code:
First of all we need to create the connection between the delegates.
Cpp.cs prepears the Delegates:
Cpp.cs
using UnityEngine;
using System;
using System.Runtime.InteropServices;
namespace Cpp
{
delegate void DelegateV();
delegate void DelegateVVi(IntPtr a, int b);
}
SimpleInterfaceCpp.cs initializes the connection:
SimpleInterfaceCpp.cs
using Cpp;
using System.Runtime.InteropServices;
using UnityEngine;
public static class SimpleInterfaceCpp
{
public static void Init()
{
initInterfaceCallbacks(
SimpleInterface.NativeLog,
SimpleInterface.Call
);
}
[DllImport(SimpleInterface.DLL)]
private static extern void initInterfaceCallbacks(
DelegateVVi native_log,
DelegateV call
);
}
Main:
MainController.cs
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class MainController : MonoBehaviour
{
void Start ()
{
SimpleInterfaceCpp.Init();
SimpleInterface.TestCalls();
}
}
SimpleInterface.cs is calling the methodes:
SimpleInterface.cs
using System;
using UnityEngine;
using System.Runtime.InteropServices;
using AOT;
using IntPtr = System.IntPtr;
using Cpp;
using StringReturn = System.IntPtr;
public class SimpleInterface
{
public const string DLL = "SimpleProjectDLL";
public static void TestCalls()
{
// This works fine
int number = getSomeInt();
Debug.Log("getSomeInt: " + number);
// This also works fine and outputs "--- A callback ---"
callSmth();
// This call gives the output "call_log: native log" but crashes afterwards !
initCallback();
}
[MonoPInvokeCallback(typeof(DelegateVVi))]
public static void NativeLog(IntPtr logMessage,
int logLevel)
{
string result = StringFromCReturn(logMessage);
UnityEngine.Debug.Log(result); // outputs "call_log: native log"
}
[MonoPInvokeCallback(typeof(DelegateV))]
public static void Call()
{
UnityEngine.Debug.Log("--- A callback---");
}
[DllImport(DLL)]
private static extern void initCallback();
[DllImport(DLL)]
private static extern void callSmth();
[DllImport(DLL)]
private static extern int getSomeInt();
public static string StringFromCReturn(StringReturn someReturnVal)
{
return Marshal.PtrToStringAnsi(someReturnVal);
}
}
Now if I create a SLN, open the project in Visual Studio and start it with the "HoloLens Emulator" I get the following Output:
getSomeInt: 42
(Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
--- A callback---
(Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
call_log: native log
(Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
The program '[1932] SimpleProject.exe' has exited with code -1073740791 (0xc0000409).
After that the App just closes.
So my Question is, does anyone know what the problem could be?
Is this the right way to use callbacks in a HoloLens Project?
Or does someone know how to find an error description for the code "-1073740791 (0xc0000409)" ?
Additional Information:
I also tried it on a real HoloLens device, same issue, so the problem does not lays at the emulator.
The error is STATUS_STACK_BUFFER_OVERRUN. The call destroyed callstack.
You have different declarations of callbacks in SimpleProjectDLL.cpp and SimpleProjectDLL.h. Cpp file uses "CPP" call conversation, header uses "C" call conversation.
You should change SimpleProjectDLL.cpp by removing
typedef void(*CB_V)();
typedef void(*CB_V_VI)(const char * a, int b);
and adding
#include "SimpleProjectDLL.h"

Interface pointers C++

I can't express my question in words. Please look the code below, I hope you will understand my question.
I have a class and an interface as shown below.
class MyInterface
{
public:
virtual ~MyInterface(){}
virtual void print() = 0;
};
class MyClass : public MyInterface
{
public:
MyClass(){}
~MyClass(){}
void print()
{
printf("Hello World\n");
}
};
Now here's my question.
MyClass* myclass = new MyClass();
myclass->print(); //will print "Hello World"
MyInterface* pMyInterface = (MyInterface*)myclass;
pMyInterface->print();
Will the second call print Hello World as well? If yes, then why?
One note is that you do not need to explicitly cast to an accessible base class, like you do in MyInterface* pMyInterface = (MyInterface*)myclass;. It is an implicit conversion from a pointer/reference to a derived class to that of an accessible base class.
In fact, such casting may introduce bugs if the classes are unrelated.
Find more details in virtual function specifier.

postgresql pqxx notify_listener - getting notify payload

Native interface postgresql provides the following command:NOTIFY channel [ , payload ], where payload is variable string. I use library pqxx for interaction with database. It provides notify_listener interface. The callback which executed as notification have just one parameter - id.
This is my code:
class notif : public pqxx::notify_listener {
public:
notif(pqxx::connection_base &conn, const std::string &table, std::shared_ptr<notify_processor_t> pr) :
pqxx::notify_listener(conn, table), _table(table), _pr(pr) {}
notif(pqxx::connection_base &conn, const std::string &table) :
pqxx::notify_listener(conn, table), _table(table) {}
virtual void operator()(int id)
{
std::cout << "notification " << _table << std::endl;
if (_pr.get())
_pr->operator()();
}
private:
std::shared_ptr<notify_processor_t> _pr;
std::string _table;
};
How I can get the payload content using pqxx interface provided?
Found the following in libpqxx 4.0.1 version:
// Obsolete notification receiver.
/** #deprecated Use notification_receiver instead.
*/
class PQXX_LIBEXPORT PQXX_NOVTABLE notify_listener
You should use notification receiver class instead of notify_listener

How come you can create an interface instance in Office Interop?

I've seen this quite a few times while using Office Interop classes
this.CustomXMLParts.Add(MyResources.Data, new Office.CustomXMLSchemaCollection());
If I hover over the CustomXMLSchemaCollection class, it shows up as an interface. Then how come I can do a new on it ? What gives?
BTW this code compiles and works.
You are not creating an instance of the CustomXMLSchemaCollection interface but an instance of the CustomXMLSchemaCollectionClass coclass.
The definition for CustomXMLSchemaCollection interface is:
[Guid("000CDB02-0000-0000-C000-000000000046")]
[CoClass(typeof(CustomXMLSchemaCollectionClass))]
public interface CustomXMLSchemaCollection : _CustomXMLSchemaCollection
{
}
This means that the designated coclass that implements the interface is CustomXMLSchemaCollectionClass. My guess is that when the C# compiler sees the new for CustomXMLSchemaCollection interface it translates it to create a COM instance of the CustomXMLSchemaCollectionClass based on the attributes provided with the interface.
After writing this simple example:
namespace ConsoleApplication2
{
using System;
using Office = Microsoft.Office.Core;
class Program
{
static void Main(string[] args)
{
Office.CustomXMLSchemaCollection test = new Office.CustomXMLSchemaCollection();
}
}
}
I just ran ildasm and get the following MSIL:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] class [Interop.Microsoft.Office.Core]Microsoft.Office.Core.CustomXMLSchemaCollection test)
IL_0000: nop
IL_0001: newobj instance void [Interop.Microsoft.Office.Core]Microsoft.Office.Core.CustomXMLSchemaCollectionClass::.ctor()
IL_0006: stloc.0
IL_0007: ret
} // end of method Program::Main
As you can see the class that is constructed is CustomXMLSchemaCollectionClass to prove my initial assumption.