Our codebase is stuck on version 0.79.1 of flow-bin and it seems that using default arguments isn't working as expected in this example:
function foo({a = 1}: {a: ?number}) {}
Playground link (be sure to set the version to 0.79.1
The error:
1: function foo({a = 1}: {a: ?number}) {}
^ null or undefined [1] is incompatible with number [2].
References:
1: function foo({a = 1}: {a: ?number}) {}
^ [1]
1: function foo({a = 1}: {a: ?number}) {}
^ [2]
However, removing the ? from the type works.
function foo({a = 1}: {a: number}) {}
When using the latest version Flow, both examples compile with no errors.
In our code, we're trying to default to null.
function foo({a = null}: {a: ?number}) {}
and this seems to fail for the same reason the first example did.
1: function foo({a = null}: {a: ?number}) {}
^ null or undefined [1] is incompatible with number [2].
Is there a way to work around this error while also defaulting a value to null, annotating that value as a Maybe type, and keeping the version unchanged?
This looks like a Flow bug to me, so if updating is not an option, then it seems like your only option is to not use default-assignment for the object pattern, in favor of doing that manually afterward, e.g.
function foo({a}: {a: ?number}) {
if (a === undefined) a = 1;
// ...
}
I'd definitely prioritize updating to a newer version of Flow, or these days even consider migrating to TS, considering how little the Flow team is able to focus on non-Facebook usage.
Related
I want to create a declarative macro that simplifies a recursive creation of an enum structure (by hiding all the Box::new). However commas seem to cause a problem when having a deep formula that has commas in its substructures.
Here is an explanation in code:
Assume this definition for an Enum representing a subset of propositional logic
#[derive(Debug)]
enum PFormula {
True,
False,
Atom(i32),
Not(Box<PFormula>),
And(Box<PFormula>, Box<PFormula>)
}
macro_rules! pformula {
($func:tt($($($sub:tt)+),+)) => { PFormula::$func($(Box::new($sub)+),+) };
(True) => { PFormula::True };
(False) => { PFormula::False };
($e:expr) => { PFormula::Atom($e) };
}
fn main() {
let x = pformula!(And(Not(2), 3));
let y = pformula!(And(And(1, 4), And(5, And(2, 6))));
println!("{:?}", x);
println!("{:?}", y);
}
The pformula should take a simplified version of the syntax defined as the enum and create a PFormula representation by hiding all the Box<PFormula>'s required for the recursive structure. What is happening is that there seems to be an ambiguity when handling the commas.
So the x in the above code should expand to:
PFormula::And(Box::new(PFormula::Not(Box::new(PFormula::Atom(2)))), Box::new(PFormula::Atom(3)))
However this is the error returned
error: local ambiguity when calling macro `pformula`: multiple parsing options: built-in NTs tt ('sub') or 1 other option.
--> src/main.rs:18:33
|
18 | let x = pformula!(And(Not(2), 3));
| ^
error: local ambiguity when calling macro `pformula`: multiple parsing options: built-in NTs tt ('sub') or 1 other option.
--> src/main.rs:19:36
|
19 | let y = pformula!(And(And(1, 4), And(5, And(2, 6))));
| ^
error: could not compile `playground` due to 2 previous errors
Please note that this is a simplification of the syntax I am actually working on. The syntax I am using has around 8 variants of arity 1 and around 5 of arity 2, so having a match arm for each variant seemed like an overkill. Additionally I tried it and it still was not working because of the commas.
So the question, is there a way to do this in declarative macros or is this better solved using function-like proc macros?
I'm trying eXist-db replication with ActiveMQ. When I configure for the consumer instance, it needs to execute a XQuery like this to register JMS receiver:
xquery version "3.0";
import module namespace replication="http://exist-db.org/xquery/replication" at "java:org.exist.jms.xquery.ReplicationModule";
let $jmsConfiguration := map {
"java.naming.factory.initial"
:= "org.apache.activemq.jndi.ActiveMQInitialContextFactory",
"java.naming.provider.url" := "tcp://localhost:61616",
"connection-factory" := "ConnectionFactory",
"destination" := "dynamicTopics/eXistdb-replication-example",
"subscriber.name" := "SubscriptionId",
"connection.client-id" := "ClientId"
}
return
replication:register($jmsConfiguration)
When I run this query, it returns an error like the title. I'm new to XQuery, so can you help me to check it ?
The notation map{ x := y, p := q } was used in an early draft of XSLT 3.0 and the notation was changed to map{ x : y, p : q } when it was adopted by XQuery. The error message suggests you are using an implementation that once supported the syntax from the draft spec, and later dropped it.
If this is actually Saxon "under the hood", then the full error message is "The ':=' notation is no longer accepted in map expressions: use ':' instead", which tells you precisely what you need to do.
Michael Kay is correct. eXist-db 4.x.x allowed the legacy draft syntax as well as the later standardised syntax. eXist-db 5.x.x oy supports the later standardised syntax.
= is redandunt, the declaration should be like this:
let $jmsConfiguration := map {
"java.naming.factory.initial" : "org.apache.activemq.jndi.ActiveMQInitialContextFactory",
"java.naming.provider.url" : "tcp://localhost:61616",
"connection-factory" : "ConnectionFactory",
"destination" : "dynamicTopics/eXistdb-replication-example",
"subscriber.name" : "SubscriptionId",
"connection.client-id" : "ClientId"
}
Flow reports that a default argument value of {} is incompatible with a generic of type {}.
Here is a minimal example:
function copy<T: {}>(o: T = {}): T {
// ^ object literal [1] is incompatible with `T` [2].
return {
...o
};
}
The docs say about the type {}:
Sometimes it is useful to write types that accept arbitrary objects,
for those you should write {}.
So in what sense are they incompatible?
T: {} means "T is any subtype of {}", or in other words, T is an object type. If it has any required properties, {} is not a value of type T.
I am trying to write a C++/Rcpp function that has an optional argument whos default needs to be a vector of length 1 with a value of 0. The following does not compile properly:
cppFunction("std::vector<int> test(std::vector<int> out = {0}) {
return out;
}")
I get the following error:
Error in cppFunction("std::vector test(std::vector out =
{1}) {\n return out;\n}") : No function definition found In
addition: Warning messages: 1: No function found for Rcpp::export
attribute at fileee5f629605d7.cpp:5 2: In sourceCpp(code = code, env
= env, rebuild = rebuild, showOutput = showOutput, : No Rcpp::export attributes or RCPP_MODULE declarations found in source
What is the right way to do this?
This answer was posted on the Rcpp issue tracker. This is the desired result that I wanted just not with std::vector.
cppFunction("IntegerVector test(IntegerVector out = IntegerVector::create(0)) {
return out;
}")
You could wrap the underlying C++ function in an R function that uses a default value:
#include <Rcpp.h>
#include <vector>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
std::vector<int> cpp_test(const std::vector<int>& x)
{
return x;
}
/*** R
test <- function(X = c(0L))
{
cpp_test(X)
}
test()
test(c(1:5))
*/
which gives you
> Rcpp::sourceCpp('~/RcppFiles/cpp_test.cpp')
> test()
[1] 0
> test(c(1:5))
[1] 1 2 3 4 5
Currently the Rcpp package didn't support the exporting the default values. There are several packages to improve this (including Rcpp11), thought, I have a solution on Rcpp with RCPP_MODULES:
library("Rcpp")
cppFunction(plugins=c("cpp11"),'NumericVector test(std::vector<int> out) {
return wrap(out);
}
RCPP_MODULE(mod) {
function("test",&test,List::create( _["out"] = std::vector<int>({0})), "Simple description");
}', verbose=TRUE,rebuild=TRUE)
I change the return type, thought, it work even if you return std::vector<int>.
So, how this works: it just creates a documentation entry with the default value, third argument for RCPP_MODULES.
With just {0} my R crashes, so, it's necessary for me to put std::vector explicitly.
Can I retrieve a Method via reflection, somehow combine it with a target object, and return it as something that looks like a function in Scala (i.e. you can call it using parenthesis)? The argument list is variable. It doesn't have to be a "first-class" function (I've updated the question), just a syntactic-looking function call, e.g. f(args).
My attempt so far looks something like this (which technically is pseudo-code, just to avoid cluttering up the post with additional definitions):
class method_ref(o: AnyRef, m: java.lang.reflect.Method) {
def apply(args: Any*): some_return_type = {
var oa: Array[Object] = args.toArray.map { _.asInstanceOf[Object] }
println("calling: " + m.toString + " with: " + oa.length)
m.invoke(o, oa: _*) match {
case x: some_return_type => x;
case u => throw new Exception("unknown result" + u);
}
}
}
With the above I was able to get past the compiler errors, but now I have a run-time exception:
Caused by: java.lang.IllegalArgumentException: argument type mismatch
The example usage is something like:
var f = ... some expression returning method_ref ...;
...
var y = f(x) // looks like a function, doesn't it?
UPDATE
Changing the args:Any* to args:AnyRef* actually fixed my run-time problem, so the above approach (with the fix) works fine for what I was trying to accomplish. I think I ran into a more general issue with varargs here.
Sure. Here's some code I wrote that add an interface to a function. It's not exactly what you want, but I think it can be adapted with few changes. The most difficult change is on invoke, where you'll need to change the invoked method by the one obtained through reflection. Also, you'll have to take care that the received method you are processing is apply. Also, instead of f, you'd use the target object. It should probably look something like this:
def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]) = method match {
case m if /* m is apply */ => target.getClass().getMethod("name", /* parameter type */).invoke(target, args: _*)
case _ => /* ??? */
}
Anyway, here's the code:
import java.lang.reflect.{Proxy, InvocationHandler, Method}
class Handler[T, R](f: Function1[T, R])(implicit fm: Manifest[Function1[T, R]]) extends InvocationHandler {
def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]) = method.invoke(f, args: _*)
def withInterface[I](implicit m: Manifest[I]) = {
require(m <:< manifest[Function1[T, R]] && m.erasure.isInterface)
Proxy.newProxyInstance(m.erasure.getClassLoader(), Array(m.erasure), this).asInstanceOf[I]
}
}
object Handler {
def apply[T, R](f: Function1[T, R])(implicit fm: Manifest[Function1[T, R]]) = new Handler(f)
}
And use it like this:
trait CostFunction extends Function1[String, Int]
Handler { x: String => x.length } withInterface manifest[CostFunction]
The use of "manifest" there helps with syntax. You could write it like this:
Handler({ x: String => x.length }).withInterface[CostFunction] // or
Handler((_: String).length).withInterface[CostFunction]
One could also drop the manifest and use classOf instead with a few changes.
If you're not looking for a generic invoke that takes the method name--but rather, you want to capture a particular method on a particular object--and you don't want to get too deeply into manifests and such, I think the following is a decent solution:
class MethodFunc[T <: AnyRef](o: Object, m: reflect.Method, tc: Class[T]) {
def apply(oa: Any*): T = {
val result = m.invoke(o, oa.map(_.asInstanceOf[AnyRef]): _*)
if (result.getClass == tc) result.asInstanceOf[T]
else throw new IllegalArgumentException("Unexpected result " + result)
}
}
Let's see it in action:
val s = "Hi there, friend"
val m = s.getClass.getMethods.find(m => {
m.getName == "substring" && m.getParameterTypes.length == 2
}).get
val mf = new MethodFunc(s,m,classOf[String])
scala> mf(3,8)
res10: String = there
The tricky part is getting the correct type for the return value. Here it's left up to you to supply it. For example,if you supply classOf[CharSequence] it will fail because it's not the right class. (Manifests are better for this, but you did ask for simple...though I think "simple to use" is generally better than "simple to code the functionality".)