The F# compiler gives an error saying I must add a project reference because the type I'm using has a method argument that lives in that project. But this method is private!
I have the following project structure:
Program -> Library -> SubLibrary
SubLibrary contains this:
namespace SubLibrary
type Widget = { Value: int }
Library contains this:
namespace Library
open SubLibrary
type Banana =
{ Value: int }
member private x.TakeWidget (w: Widget) = ()
Program contains this:
open Library
[<EntryPoint>]
let main argv =
printfn "%A" argv
let banana = { Value = 42 }
0
I get this error:
error FS0074:
The type referenced through 'SubLibrary.Widget' is defined in an assembly that is not referenced.
You must add a reference to assembly 'SubLibrary'
But the TakeWidget method is private!
I tried changing Banana into a class, rather than a record, but that made no difference.
As an experiment, I created a C# version of Library, called CLibrary:
using SubLibrary;
namespace CLibrary {
public class CBanana {
int m_value;
public CBanana(int value) {
m_value = value;
}
private void TakeWidget(Widget w) {
}
}
}
Then I changed Program to use CBanana instead of Banana:
open Library
[<EntryPoint>]
let main argv =
printfn "%A" argv
let banana = CBanana 42
0
Now I don't get an error. In fact, with C# I can make that method public, and so long as I don't try to compile a call to it, there is no error.
Why is the compiler insisting I add a reference to SubLibrary? Sure, I could just go ahead and do what it tells me to do, for a quiet life, but SubLibrary is a private implementation detail of Library, which should not be exposed to Program.
Actually, when I tried with a class instead of record, it did the trick (F# 3.1):
type BananaClass (value:int) =
member private x.TakeWidget (w: Widget) = ()
member x.Value = value
You can work around it with a record as well - you need to move the private member into a separate module and have it as a type augmentation:
type Banana = { Value: int }
module Ext =
type Banana with
member x.TakeWidget (w: Widget) = ()
Compiler won't complain about the missing dependency until you open the Ext module.
I don't have a good idea why the compiler was complaining in the first place. Probably one of its quirks. I couldn't find anything seriously suspicious in the generated IL (other than a surprising fact that F# compiler marks both private and internal members as internal in the IL - this turned out to be of no consequence here).
Indeed this to me looks like an error I have raised an issue here, https://github.com/Microsoft/visualfsharp/issues/86. So you'll be able to track feedback from there.
Related
I'm using rust for windows to use the win32 API.
However, I need to initialize com library to use some windows APIs, but I cannot find some classes ID (CLSID), to create an instance.
I need to find the Speech ISpVoice CLSID to use in my instance creation.
CLSID_SpVoice is the CLSID.
Also, I cannot find some macros like "FAILED", and "SUCCEEDED".
If anyone can direct me, that would be appreciated!
Also, if there's any error in my code, please highlight it me.
Code:
use windows::Win32::System::Com::{CoInitializeEx, CoCreateInstance};
use windows::Win32::System::{Com, Ole};
use windows::core::{ HRESULT, Error };
use windows::Win32::Media::Speech::ISpVoice;
fn main() {
let speaker: ISpVoice;
unsafe {
if CoInitializeEx(std::ptr::null(), Com::COINIT_MULTITHREADED) ==Result::Ok(()) {
let hr: HRESULT = CoCreateInstance(, punkouter, dwclscontext)
}
}
}
If anything is unclear, please let me know!
The windows crate declares the SpVoice constant which is the value of the CLSID_SpVoice class ID. As you have discovered, that's the CLSID you want to pass into CoCreateInstance.
The latter returns a windows::core::Result<T>, which models the same semantics as C code using the SUCCEEDED and FAILED macros would. You can either match on the Ok or Err variants manually, or use the ? operator for convenient error propagation:
use std::ptr;
use windows::{
core::Result,
Win32::{
Media::Speech::{ISpVoice, SpVoice},
System::Com::{CoCreateInstance, CoInitializeEx, CLSCTX_ALL, COINIT_APARTMENTTHREADED},
},
};
fn main() -> Result<()> {
unsafe { CoInitializeEx(ptr::null(), COINIT_APARTMENTTHREADED) }?;
let _speaker: ISpVoice = unsafe { CoCreateInstance(&SpVoice, None, CLSCTX_ALL) }?;
Ok(())
}
In case you need a CLSID that's not available through the windows crate, you can always construct a GUID constant using either from_values or from_u128:
const CLSID_SpVoice: GUID = GUID::from_u128(0x96749377_3391_11d2_9ee3_00c04f797396);
Note that the value is exactly the value you were given in a comment. Your assessment that C++ and Rust were any different with respect to COM is unfounded. They are indeed the same thing, just with different syntax.
I found the solution.
I'll let my answer for anyone may encounter this problem:
Instead of providing the Class ID of the ISpVoice, I referenced the SpVoice struct to the CoCreateInstance method then it returns the SpVoice struct.
As following:
let speaker: ISpVoice = CoCreateInstance(&SpVoice, None, CLSCTX_ALL)?;
This method will work with any CoCreateInstance.
However, I'm still stuck with the two macros: "FAILED", and "SUCCEEDED".
If anyone know, please let me know also.
I am trying to fast forward time to do some tests for a custom runtime module. I have looked at the answer from this thread and followed the answer to use Timestamp, however, I am unable to access the set_timestamp method.
setup:
#[cfg(test)]
mod tests {
use super::*;
use support::dispatch::Vec;
use runtime_primitives::traits::{Hash};
use runtime_io::with_externalities;
use primitives::{H256, Blake2Hasher};
use timestamp;
use support::{impl_outer_origin, assert_ok, assert_noop};
use runtime_primitives::{
BuildStorage,
traits::{BlakeTwo256, IdentityLookup},
testing::{Digest, DigestItem, Header}
};
impl_outer_origin! {
pub enum Origin for Test {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl system::Trait for Test {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = ();
type Log = DigestItem;
}
impl super::Trait for Test {
type Event = ();
}
impl timestamp::Trait for Test {
type Moment = u64;
type OnTimestampSet = ();
}
type Pizza = Module<Test>;
And the error is below:
error[E0599]: no function or associated item named `set_timestamp` found for type
`srml_timestamp::Module<tests::Test>` in the current scope
|
254 | let now = <timestamp::Module<tests::Test>>::set_timestamp(9);
| ^^^^^^^^^^^^^ function or associated item
not found in `srml_timestamp::Module<tests::Test>`
In Substrate v1.0, the set_timestamp function has a #[cfg(feature = "std")] attribute on it:
https://github.com/paritytech/substrate/blob/v1.0/srml/timestamp/src/lib.rs#L276
This means it will only be visible if you are compiling with std. When you write tests, this should work, but I assume that this issue is appearing because you are trying to call it from within the runtime environment, which much be no_std.
If for some reason you do need to modify the timestamp from within your runtime, you should be able to do so directly:
https://github.com/paritytech/substrate/blob/v1.0/srml/timestamp/src/lib.rs#L249
<timestamp::Module<T>>::Now::put(new_time)
(I haven't tested this, but something like it should work).
Let me know if this helps.
In Substrate v1.0 you can declare
type Moment = timestamp::Module<Test>;
Then use it to set a specific timestamp.
Moment::set_timestamp(9);
If you want to get the timestamp value, you can do:
let now_timestamp = Moment::now();
We use a third party Tcl parsing library to validation Tcl script for both syntax and semantic checking. The driver was written in C and defined a set of utility functions. Then it calls Tcl_CreateObjCommand so the script could call these C functions. Now we are in the process of porting the main program to go and I could not find a way to do this. Anyone know a way to call golang functions from Tcl script?
static int
create_utility_tcl_cmds(Tcl_Interp* interp)
{
if (Tcl_CreateObjCommand(interp, "ip_v4_address",
ip_address, (ClientData)AF_INET, NULL) == NULL) {
TCL_CHECKER_TCL_CMD_EVENT(0, "ip_v4_address");
return -1;
}
.....
return 0;
}
Assuming you've set the relevant functions as exported and built the Go parts of your project as in
Using Go code in an existing C project
[…]
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
Then the core of what remains to be done is to write the C glue function from Tcl's API to your Go code. That will involve a function something like:
static int ip_address_glue(
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) {
// Need an explicit cast; ClientData is really void*
GoInt address_family = (GoInt) clientData;
// Check for the right number of arguments
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "address");
return TCL_ERROR;
}
// Convert the argument to a Go string
GoString address;
int len;
address.p = Tcl_GetStringFromObj(objv[1], &len);
address.n = len; // This bit is hiding a type mismatch
// Do the call; I assume your Go function is called ip_address
ip_address(address_family, address);
// Assume the Go code doesn't fail, so no need to map the failure back to Tcl
return TCL_OK;
}
(Credit to https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf for providing enough information for me to work out some of the type bindings.)
That's then the function that you register with Tcl as the callback.
Tcl_CreateObjCommand(interp, "ip_v4_address", ip_address_glue, (ClientData)AF_INET, NULL);
Theoretically, a command registration can fail. Practically, that only happens when the Tcl interpreter (or a few critical namespaces within it) is being deleted.
Mapping a failure into Tcl is going to be easiest if it is encoded at the Go level as an enumeration. Probably easiest to represent success as zero. With that, you'd then do:
GoInt failure_code = ip_address(address_family, address);
switch (failure_code) {
case 0: // Success
return TCL_OK;
case 1: // First type of failure
Tcl_SetResult(interp, "failure of type #1", TCL_STATIC);
return TCL_ERROR;
// ... etc for each expected case ...
default: // Should be unreachable, yes?
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unexpected failure: %d", failure_code));
return TCL_ERROR;
}
Passing back more complex return types with tuples of values (especially a combination of a success indicator and a “real” result value) should also be possible, but I've not got a Go development environment in order to probe how they're mapped at the C level.
Basically, I am looking for something more or less equivalent to the following C code:
int theGlobalCount = 0;
int
theGlobalCount_get() { return theGlobalCount; }
void
theGlobalCount_set(int n) { theGlobalCount = n; return; }
You could use a neat trick: declare a mutable global variable, and make a ref (aka mutable reference) point to it (no GC is required to make this work!). Then, implement functions to provide access to the mutable reference.
local
var theGlobalCount_var : int = 0
val theGlobalCount = ref_make_viewptr (view# theGlobalCount_var | addr# theGlobalCount_var)
in // in of [local]
fun
theGlobalCount_get () : int = ref_get_elt (theGlobalCount)
fun
theGlobalCount_set (n: int): void = ref_set_elt (theGlobalCount, n)
end // end of [local]
Note that declarations inside local-in are visible only to code inside in-end. Therefore, neither theGlobalCount_var nor theGlobalCount are visible outside the scope of the local.
Full code: glot.io
You can also use the extvar feature to update an external global variable (declared in the target language). This is very useful if you compile ATS to a language that does not support explicit pointers (e.g., JavaScript). Here is a running example that makes use of this feature:
http://www.ats-lang.org/SERVER/MYCODE/Patsoptaas_serve.php?mycode_url=http://pastebin.com/raw/MsXhVE0A
Given the following simplified program:
#[macro_use] extern crate log;
extern crate ansi_term;
extern crate fern;
extern crate time;
extern crate threadpool;
extern crate id3;
mod logging;
use std::process::{exit, };
use ansi_term::Colour::{Yellow, Green};
use threadpool::ThreadPool;
use std::sync::mpsc::channel;
use std::path::{Path};
use id3::Tag;
fn main() {
logging::setup_logging();
let n_jobs = 2;
let files = vec!(
"/tmp/The Dynamics - Version Excursions/01-13- Move on Up.mp3",
"/tmp/The Dynamics - Version Excursions/01-09- Whole Lotta Love.mp3",
"/tmp/The Dynamics - Version Excursions/01-10- Feel Like Making Love.mp3"
);
let pool = ThreadPool::new(n_jobs);
let (tx, rx) = channel();
let mut counter = 0;
for file_ in files {
let file_ = Path::new(file_);
counter = counter + 1;
let tx = tx.clone();
pool.execute(move || {
debug!("sending {} from thread", Yellow.paint(counter.to_string()));
let tag = Tag::read_from_path(file_).unwrap();
let a_name = tag.artist().unwrap();
debug!("recursed file from: {} {}",
Green.paint(a_name), file_.display());
tx.send(".").unwrap();
// TODO amb: not working..
// tx.send(a_name).unwrap();
});
}
for value in rx.iter().take(counter) {
debug!("receiving {} from thread", Green.paint(value));
}
exit(0);
}
Everything works as expected, unless the one commented line (tx.send(a_name).unwrap();) is put back in. In that case I get the following error:
error: `tag` does not live long enough
let a_name = tag.artist().unwrap();
^~~
note: reference must be valid for the static lifetime...
note: ...but borrowed value is only valid for the block suffix following statement 1 at 39:58
let tag = Tag::read_from_path(file_).unwrap();
let a_name = tag.artist().unwrap();
debug!("recursed file from: {} {}",
Green.paint(a_name), file_.display());
...
Generally I understand what the compiler tells me, but I don't see a problem since the variable tag is defined inside of the closure block. The only problem that I can guess is, that the variable tx is cloned outside and therefore can collide with the lifetime of tag.
My goal is to put all the current logic in the thread-closure inside of the thread, since this is the "processing" I want to spread to multiple threads. How can I accomplish this, but still send some value to the longer existing tx?
I'm using the following Rust version:
$ rustc --version
rustc 1.9.0 (e4e8b6668 2016-05-18)
$ cargo --version
cargo 0.10.0-nightly (10ddd7d 2016-04-08)
a_name is &str borrowed from tag. Its lifetime is therefore bounded by tag. Sending non 'static references down a channel to another thread is unsafe. It refers to something on the threads stack which might not even exist anymore once the receiver tries to access it.
In your case you should promote a_name to an owned value of type String, which will be moved to the receiver thread.
tx.send(a_name.to_owned()).unwrap();