Converting Rust macro types into expressions - macros

I'd like to assume a given type implements some trait (e.g. Default) with a method (e.g. default()). I want to call that method and store its value into a local variable. Here is a general idea of it:
macro_rules! get_default {
( $x:ty = $alias:ident ) => {
let $alias = $x::default();
};
}
fn main() {
// get_default!(i32 = z);
// println!("get_default! {:?} ", z);
println!("i32 default {:?} ", i32::default());
}
Playground link.
When I try that I get an error:
error: expected expression, found `i32`
--> <anon>:3:22
|>
3 |> let $alias = $x::default();
|> ^^
I understand it's because it expects an expression, but I want to limit input to types only. Is there a way to turn $x from ty to expr, or a way to call a method on a type (even if it's potentially missing).

You were almost there. You can hint the expected default type to the compiler and then just use the universal function call syntax:
macro_rules! get_default {
( $x:ty = $alias:ident ) => {
let $alias = <$x as Default>::default();
};
}
fn main() {
get_default!(i32 = z);
println!("get_default! {:?} ", z);
println!("i32 default {:?} ", i32::default());
}
(Playground link)
The key bit is this:
let $alias = <$x as Default>::default();
This casts $x to the Default trait and then invokes the default() method, as you needed.
You can also use a shorthand when you don't need to disambiguate between traits:
let $alias = <$x>::default();
(Playground link)
More General Usage of UFCS
Using UFCS as shown above, you can disambiguate between traits that implement the same methods. This is the 'angle-bracket form' which is useful if the default() method is implemented in two traits.
In this specific scenario, you can also use UFCS more specifically, like so:
let $alias: $x = Default::default();
That alone provides enough information for Rust to infer the correct impl.
(Playground link)

Related

F# Async<_> to Async<obj>

I am working with F# to develop PowerShell tooling. I am currently running into a block because Async<_>is a generic type that is not derived from a non-generic type, so I can't request an Async<_> or Async as a parameter value - I have to specify the exact generic type parameter.
(For those unfamiliar with the interaction between these two languages, I can write a class in a .NET language such as F#, derive it from a class in the PowerShell library, and give it a specific attribute and when I run PowerShell and import my library, my class is exposed as a command. The command type can't be generic. Properties of the type are exposed as PowerShell parameters.)
As far as I'm aware I can't avoid this by having a generic member on a non-generic type, so ideally I'd have a transformation attribute (for non-PS users, transformation attributes effectively perform type conversion during runtime parameter binding) to turn Async<_> into Async<obj>. For the most part, this would work great for me. However, I can't figure out a way to check if a value is Async<_>, because the check computation :? Async<_> at compile time ends up as computation :? Async<obj>, which is not, unfortunately, the same, and returns false when passed Async<int>.
I ran into a similar issue in C# and was able to leverage the dynamic keyword after running a reflection test, and making the parameter be of the derived base type System.Threading.Tasks.Task, e.g.
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHeirarchy;
var isTaskOf = task.GetType()
.GetProperty("GetAwaiter", flags)
.PropertyType
.GetMethod("GetResult", flags)
.ReturnType != typeof(void);
if (isTaskOf) {
var result = await (dynamic)task;
}
I am willing to do something like this in F# if possible, but:
I have not ben able to successfully get the dynamic lookup operator ? to compile. Specifically, "none of the types 'Async<'a>, string' support the '?' operator". Not sure what I'm doing wrong as the explanations look straightforward and I can't find any other reports of this message or requirements for that operator.
I don't know if that would even work or if that operator is only used to dynamically access a member of an object.
The solutions I have tried are:
/// Transform from Async<_> to Async<obj>
override _.Transform(_, item : obj) : obj =
match item with
// only matches Async<obj>. I get a compiler warning that _ is constrained to obj
| :? Async<_> as computation ->
let boxedComputation : Async<obj> = async { return! computation }
boxedComputation
// if the value is not an async computation, let it pass through. This will allow other transformation or type converters to try to convert the value
| _ -> item
override _.Transform(_, item) =
// no compiler warning about the type being constrained to obj, but the if test does not pass unless item is Async<obj>
if (item :? Async<_>) then async { return! item :?> Async<_> }
else item
The other thing I can think of is to use reflection entirely - get the async type, call all of the AsyncBuilder methods reflectively to create a computation expression, and then cast it to Async. As I'm fairly new to F# I'm not sure how well I'd be able to piece together a computation expression like that, and either way it seems a lot more complicated than it ought to be. I'm hoping there is some better way to identify the return type of an async computation and/or just box the result without caring what type it actually is.
EDIT
After trying something ridiculously complicated using reflection with the AsyncBuilder type I realized I could leverage it a little more simply. Here is my current working solution, but I'm still looking out for any better options.
static let boxAsyncReturnValue v = async { return v :> obj }
static let bindFunctionReflected = typeof<FSharpAsyncObjTransformationAttribute>.GetMethod(
nameof boxAsyncReturnValue,
BindingFlags.NonPublic ||| BindingFlags.Static
)
override _.Transform(engineIntrinsics, item) =
// I need to identify the current return type of the computation, and quit if "item" is not Async<_>
if item = null then item else
let itemType = item.GetType()
if not itemType.IsGenericType then item else
let genericItemType = itemType.GetGenericTypeDefinition()
if genericItemType <> typedefof<Async<_>> then item else
let returnType = itemType.GetGenericArguments()[0]
if returnType = typeof<obj> then item else
bindFunctionReflected.MakeGenericMethod(itemType).Invoke(null, [|item|])
This is how I would do it:
let convert (a: Async<_>) =
async {
let! x = a
return box x
}
And at compile time it behaves as you'd expect:
let a = async { return "hello" }
let o: Async<obj> = convert a
let res = Async.RunSynchronously o
printfn "%s" res // Error: expected type 'string' but is type 'obj'
printfn "%s" (unbox<string> res) // compiles, prints the string

"type of expression is ambiguous without more context" error in Swift closure

I'm getting a strange type-related error in my Swift code:
type of expression is ambiguous without more context.
This happens even if I provide the full type information.
Here's the code that reproduces it.
I have 2 structures:
struct Person{
let name_ : String
let address_ : Address
}
struct Address {
let street_ : String
let city_ : String
}
I then create a structure that contains 2 functions to get and set the address of a Person:
struct Lens<A,B> {
let extract: (A)->B
let create: (B,A) -> A
}
When I try to create an instance of Lens that gets and sets the address (in the later case it returns a new Person with the new address), I get the error in the first closure.
let lens : Lens<Person, Address> =
Lens(
extract: {(p:Person)->Address in
return p.address_}, // here's the error
create: {Person($0.name_,
Address(street_: $1, city_: $0.address_.city_))})
Not only the type of the parameter of the first closure is specified in the type for lens, but also in the closure itself.
What's going on????
While it suggests the error is in extract, it really was in create. The $0 and $1 are backwards. You're referring to $0.name_, but $0 of the create closure is B, the Address, but name_ is a property of Person. I think you meant:
let lens : Lens<Person, Address> = Lens(
extract: { $0.address_ },
create: { Person(name_: $1.name_, address_: Address(street_: $0.street_, city_: $1.address_.city_)) }
)
Or you can redefine Lens:
struct Lens<A, B> {
let extract: (A) -> B
let create: (A, B) -> A // note, A & B swapped
}
And then you can do:
let lens : Lens<Person, Address> = Lens(
extract: { $0.address_ },
create: { Person(name_: $0.name_, address_: Address(street_: $1.street_, city_: $0.address_.city_)) }
)
Or, perhaps you meant:
let lens : Lens<Person, Address> = Lens(
extract: { $0.address_ },
create: { Person(name_: $0.name_, address_: $1) }
)
That way, the create uses both the street and city of the supplied address. (It doesn't make sense to me to use the street of the address, but not the city.)
Your initialization of lens will work using a form like the following:
let lens = Lens<Person, Address>(
extract: {p in p.address_},
create: {(a,p) in Person(name_: p.name_, address_: Address(street_: a.street_, city_: p.address_.city_))})
As Martin R noted, the sole error were in fact in the create closure. When you call the default initializers for your struct, you need to supply the external names (=internal names) for all arguments (even the first one), by default (this differs from regular functions where you may omit the external name for the first function argument). Also make sure you supply the correct argument types for the initializer.
Note from above that you needn't supply the closure type ((p:Person)->Address in ...), as Swift can infer (and expects this) from the closure: p in ... suffices (see example above). Or, even more condensed, omit explicit variable names in you closures and make use of $0 and $1 (expected arguments) references instead, as in Robs solution.

What does an ampersand (&) mean in the Swift language?

I know about the ampersand as a bit operation but sometimes I see it in front of variable names. What does putting an & in front of variables do?
It works as an inout to make the variable an in-out parameter. In-out means in fact passing value by reference, not by value. And it requires not only to accept value by reference, by also to pass it by reference, so pass it with & - foo(&myVar) instead of just foo(myVar)
As you see you can use that in error handing in Swift where you have to create an error reference and pass it to the function using & the function will populate the error value if an error occur or pass the variable back as it was before
Why do we use it? Sometimes a function already returns other values and just returning another one (like an error) would be confusing, so we pass it as an inout. Other times we want the values to be populated by the function so we don't have to iterate over lots of return values, since the function already did it for us - among other possible uses.
It means that it is an in-out variable. You can do something directly with that variable. It is passed by address, not as a copy.
For example:
var temp = 10
func add(inout a: Int){
a++
}
add(inout:&temp)
temp // 11
There's another function of the ampersand in the Swift language that hasn't been mentioned yet. Take the following example:
protocol Foo {}
protocol Bar {}
func myMethod(myVar: Foo & Bar) {
// Do something
}
Here the ampersand syntax is stating that myVar conforms to both the Foo and Bar protocol.
As another use case, consider the following:
func myMethod() -> UIViewController & UITableViewDataSource {
// Do something
}
Here we're saying that the method returns a class instance (of UIViewController) that conforms to a certain protocol (UITableViewDataSource). This is rendered somewhat obsolete with Swift 5.1's Opaque Types but you may see this syntax in pre-Swift 5.1 code from time to time.
If you put & before a variable in a function, that means this variable is inout variable.
#Icaro already described what it means, I will just give an example to illustrate the difference between inout variables and in variables:
func majec(inout xValue:Int, var yValue:Int) {
xValue = 100
yValue = 200
}
var xValue = 33
var yValue = 33
majec(&xValue, yValue: yValue)
xValue //100
yValue //33
As noted in other answers, you use prefix & to pass a value to an inout parameter of a method or function call, as documented under Functions > Function Argument Labels and Parameter Names > In-Out Parameters in The Swift Programming Language. But there's more to it than that.
You can, in practice, think about Swift inout parameters and passing values to them as being similar to C or C++ pass-by-address or pass-by-reference. In fact, the compiler will optimize many uses of inout parameters down to roughly the same mechanics (especially when you're calling imported C or ObjC APIs that deal in pointers). However, those are just optimizations — at a semantic level, inout really doesn't pass addresses around, which frees the compiler to make this language construct more flexible and powerful.
For example, here's a struct that uses a common strategy for validating access to one of its properties:
struct Point {
private var _x: Int
var x: Int {
get {
print("get x: \(_x)")
return _x
}
set {
print("set x: \(newValue)")
_x = newValue
}
}
// ... same for y ...
init(x: Int, y: Int) { self._x = x; self._y = y }
}
(In "real" code, the getter and setter for x could do things like enforcing minimum/maximum values. Or x could do other computed-property tricks, like talking to a SQL database under the hood. Here we just instrument the call and get/set the underlying private property.)
Now, what happens when we pass x to an inout parameter?
func plusOne(num: inout Int) {
num += 1
}
var pt = Point(x: 0, y: 1)
plusOne(num: &pt.x)
// prints:
// get x: 0
// set x: 1
So, even though x is a computed property, passing it "by reference" using an inout parameter works the same as you'd expect it to if x were a stored property or a local variable.
This means that you can pass all sorts of things "by reference" that you couldn't even consider in C/C++/ObjC. For example, consider the standard library swap function, that takes any two... "things" and switches their values:
var a = 1, b = 2
swap(&a, &b)
print(a, b) // -> 2 1
var dict = [ "Malcolm": "Captain", "Kaylee": "Mechanic" ]
swap(&dict["Malcolm"], &dict["Kaylee"])
print(dict) // -> ["Kaylee": "Captain", "Malcolm": "Mechanic"], fanfic ahoy
let window1 = NSWindow()
let window2 = NSWindow()
window1.title = "window 1"
window2.title = "window 2"
var windows = [window1, window2]
swap(&windows[0], &windows[1])
print(windows.map { $0.title }) // -> ["window 2", "window 1"]
The the way inout works also lets you do fun stuff like using the += operator on nested call chains:
window.frame.origin.x += 10
... which is a whole lot simpler than decomposing a CGRect just to construct a new one with a different x coordinate.
This more nuanced version of the inout behavior, called "call by value result", and the ways it can optimize down to C-style "pass by address" behavior, is covered under Declarations > Functions > In-Out Parameters in The Swift Programming Language.

In Haxe, how do you read a variable name inside of a Macro?

I'm trying to use Macros to convert some variable declarations from this:
function test():Void {
var someComp:Component = __SOME_MACRO__();
// Or...
#getCompById var someComp:Component;
// Or even simpler...
getCompById(someComp, Component); //do some fancy macro magic...
// Also, if it's not possible/easy with a variable ...
getCompById("someComp", Component); //with a string of the variable name.
}
... to this:
function test() {
var someComp:Component = cast container.getCompById("someComp");
}
I'm leaning more toward the 3rd option (shorter syntax, same results).
But I have no idea how to write the macro (should it take a String as parameter? An expression?) and how to properly return that as a macro expression.
This is the (broken) code I've got so far:
macro static function getCompById(someVar:Expr, typeVar:Expr) {
return macro {
var someVar:typeVar = cast container.getCompById("someVar");
};
}
Any ideas?
The issue with the code you posted is first that you'd need reification escaping mechanisms for this to work correctly - so the first change would be to use the macro escapes:
return macro var $someVar:$typeVar = cast container.getCompById($v{someVar});
Now there will be some problems with this: It's expecting someVar to be of type String, and typeVar to be of type ComplexType. It's easy to get the string component from an Expr. It's not so easy however to transform an Expr into ComplexType. The easiest way to do that is to use the tink_macros library and use asComplexType
So the (untested) code will look something like:
using tink.MacroAPI;
using haxe.macro.Tools;
macro static function getCompById(someVarExpr:Expr, typeVarExpr:Expr)
{
var typeVar = typeVarExpr.toString().asComplexType();
switch (someVarExpr.getIdent())
{
case Success(someVar):
return macro var $someVar:$typeVar = cast container.getCompById($v{someVar});
case Failure(error): throw error;
}
}

F# Class with Generics : 'constructor deprecated' error

I am trying to create a a class that will store a time series of data - organized by groups, but I had some compile errors so I stripped down to the basics (just a simple instantiation) and still can't overcome the compile error. I was hoping some one may have seen this issue before. Clas is defined as:
type TimeSeriesQueue<'V, 'K when 'K: comparison> = class
val private m_daysInCache: int
val private m_cache: Map<'K, 'V list ref > ref;
val private m_getKey: ('V -> 'K) ;
private new(getKey) = {
m_cache = ref Map.empty
m_daysInCache = 7 ;
m_getKey = getKey ;
}
end
So that looks OK to me (it may not be, but doesnt have any errors or warnings) - the instantiation gets the error:
type tempRec = {
someKey: string ;
someVal1: int ;
someVal2: int ;
}
let keyFunc r:tempRec = r.someKey
// error occurs on the following line
let q = new TimeSeriesQueue<tempRec, string> keyFunc
This construct is deprecated: The use
of the type syntax 'int C' and 'C
' is not permitted here. Consider
adjusting this type to be written in
the form 'C'
NOTE This may be simple stupidity - I am just getting back from holiday and my brain is still on time zone lag...
The compiler is just saying that you need to enclose parameters of the constructor in parentheses:
// the following should work fine
let q = new TimeSeriesQueue<tempRec, string>(keyFunc)
There are some other issues though - the constructor needs to be public (otherwise you cannot call it) and the parameter of keyFunc should be also in parentheses (otherwise, the compiler will think that the type annotation is for the result of the function):
let keyFunc (r:tempRec) = r.someKey
You may also consider using implicit constructor syntax which makes class declarations a lot simpler in F#. Parameters of the constructor automatically become available in the body of the class and you can declare (private) fields simply using let:
type TimeSeriesQueue<'V, 'K when 'K: comparison>(getKey : 'V -> 'K) =
let daysInCache = 7
let cache = ref Map.empty
member x.Foo() = ()