Why can't you modify closure parameters of inline methods? - haxe

I've got this section of code:
class Main {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
if (f == null) {
f = (a, b) -> a - b;
}
return f(a, b);
}
static function main() {
trace(difference(42, 37));
trace(difference(42, 37, (a, b) -> a - b));
}
}
Which, when I compile using haxe --main Main, fails with this error:
Main.hx:11: characters 15-50 : Cannot modify a closure parameter inside inline method
Main.hx:11: characters 15-50 : For function argument 'v'
If I change Main.difference to not be inline, this error doesn't come up and everything compiles fine.
Why does this error occur?
Edit: I've found out I can also assign the argument to a variable first, and then pass the variable to Main.difference, like this:
static function main() {
var f = (a, b) -> a - b;
trace(difference(42, 37, f));
}
Which works fine with Main.difference being inlined. How does assigning the function to a variable first change things though?

This is related to how inline functions are unwrapped by the compiler. Let us take a simpler variant of your code:
class HelloWorld {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
return f(a, b);
}
static function main() {
trace(difference(42, 37, (a, b) -> a - b));
}
}
When disabling optimizations, this will yield the following JavaScript:
HelloWorld.main = function() {
console.log("HelloWorld.hx:14:",(function(a,b) {
return a - b;
})(42,37));
};
So the body of difference has been incorporated into main using a JavaScript closure. My best guess for what is happnening in your exact case is something like this:
HelloWorld.main = function() {
var v = function(a,b) {
return a - b;
}
console.log("HelloWorld.hx:14:", (function(a,b) {
if (v == null) {
v = function(a, b) {
return a - b;
}
}
return v(a, b);
})(42, 37));
};
This alters the value of v, which exists outside of difference, which has been automatically placed there as a binding for the anonymous lambda. This is what the compiler is trying to avoid. This would not be the end of the world in your case, but in general this is bad and would lead to issues in many programs.
There is a way to inline this code perfectly by hand without this, but I think that there is some weirdness surrounding how annonymous lambdas are currently handled. The situation may improve in the future.
When you explicitly defined f in main, the compiler is intelligent enough to rename the nested f as f1, which is why the issue does not occur:
HelloWorld.main = function() {
var f = function(a,b) {
return a - b;
};
var f1 = f;
if(f1 == null) {
f1 = function(a,b) {
return a - b;
};
}
console.log("HelloWorld.hx:14:",f1(42,37));
};
But this would also work if the inline part of this function is important to you:
class HelloWorld {
static inline function difference(a:Int, b:Int, ?f:(Int, Int) -> Int):Int {
var h = f;
if (h == null) {
h = (a, b) -> a - b;
}
return h(a, b);
}
static function main() {
trace(difference(42, 37, (a, b) -> a - b));
}
}

Related

How to multiply strings in Haxe

I'm trying to multiply some string a by some integer b such that a * b = a + a + a... (b times). I've tried doing it the same way I would in python:
class Test {
static function main() {
var a = "Text";
var b = 4;
trace(a * b); //Assumed Output: TextTextTextText
}
}
But this raises:
Build failure Test.hx:6: characters 14-15 : String should be Int
There doesn't seem to be any information in the Haxe Programming Cookbook or the API Documentation about multiplying strings, so I'm wondering if I've mistyped something or if I should use:
class Test {
static function main() {
var a = "Text";
var b = 4;
var c = "";
for (i in 0...b) {
c = c + a;
}
trace(c); // Outputs "TextTextTextText"
}
}
Not very short, but array comprehension might help in some situations :
class Test {
static function main() {
var a = "Text";
var b = 4;
trace( [for (i in 0...b) a].join("") );
//Output: TextTextTextText
}
}
See on try.haxe.org.
The numeric multiplication operator * requires numeric types, like integer. You have a string. If you want to multiply a string, you have to do it manually by appending a target string within the loop.
The + operator is not the numeric plus in your example, but a way to combine strings.
You can achieve what you want by operator overloading:
abstract MyAbstract(String) {
public inline function new(s:String) {
this = s;
}
#:op(A * B)
public function repeat(rhs:Int):MyAbstract {
var s:StringBuf = new StringBuf();
for (i in 0...rhs)
s.add(this);
return new MyAbstract(s.toString());
}
}
class Main {
static public function main() {
var a = new MyAbstract("foo");
trace(a * 3); // foofoofoo
}
}
To build on tokiop's answer, you could also define a times function, and then use it as a static extension.
using Test.Extensions;
class Test {
static function main() {
trace ("Text".times(4));
}
}
class Extensions {
public static function times (str:String, n:Int) {
return [for (i in 0...n) str].join("");
}
}
try.haxe.org demo here
To build on bsinky answer, you can also define a times function as static extension, but avoid the array:
using Test.Extensions;
class Test {
static function main() {
trace ("Text".times(4));
}
}
class Extensions {
public static function times (str:String, n:Int) {
var v = new StringBuf();
for (i in 0...n) v.add(str);
return v.toString();
}
}
Demo: https://try.haxe.org/#e5937
StringBuf may be optimized for different targets. For example, on JavaScript target it is compiled as if you were just using strings https://api.haxe.org/StringBuf.html
The fastest method (at least on the JavaScript target from https://try.haxe.org/#195A8) seems to be using StringTools._pad.
public static inline function stringProduct ( s : String, n : Int ) {
if ( n < 0 ) {
throw ( 1 );
}
return StringTools.lpad ( "", s, s.length * n );
}
StringTools.lpad and StringTools.rpad can't seem to decide which is more efficient. It looks like rpad might be better for larger strings and lpad might be better for smaller strings, but they switch around a bit with each rerun. haxe.format.JsonPrinter uses lpad for concatenation, but I'm not sure which to recommend.

SequenceType of functions

I have a swift implementation of the haskell <*> operator that seems to work as long as the arguments are arrays:
public func <*> <T, U>(left:[(T)->U], right:[T]) -> [U] {
return flatten(map(left) { (function) -> [U] in
return map(right) { return function($0) }
})
}
I'm trying to make it more general by rewriting it to use sequences instead of arrays, but I'm having difficulty with the syntax to require that a sequence be a sequence of functions. This works to generalize the right argument, but not the left:
public func <*> <T, U, Tseq:SequenceType where Tseq.Generator.Element == T>(left:[(T)->U], right:Tseq) -> [U] {
return flatten(map(left) { (function) -> [U] in
return map(right) { return function($0) }
})
}
Now I'm trying to generalize the left part, but running into syntax errors. It seems like it ought to be:
public func <*> <
T,
U,
Tseq:SequenceType where Tseq.Generator.Element == T,
Fseq:SequenceType where Fseq.Generator.Element == (T) -> U
>(left:[(T)->U], right:Tseq) -> [U] {
return flatten(map(left) { (function) -> [U] in
return map(right) { return function($0) }
})
}
But that gives me an error on the Fseq... line:
Expected '>' to complete generic parameter list
What is the proper syntax (or is there no proper syntax) to require that Fseq.Generator.Element be a function taking a T and returning a U?
Couple of problems (one fixable, one more fatal):
You have the syntax for the generic template a bit off. There’s only one where clause for all the placeholders, rather than an optional one per placeholder. So it would be more like:
public func <*> <
T, U, Tseq: SequenceType, Fseq: SequenceType
where Fseq.enerator.Element == T -> U,
Tseq.Generator.Element == T>
(left:[(T)->U], right:Tseq) -> [U] {
return flatten(map(left) { (function) -> [U] in
return map(right) { return function($0) }
})
}
However, that still won’t work because you can’t have expressions more complex than single types on the rhs of a == (not even tuples of two placeholders). So where Fseq.Generator.Element == T->U is not going to fly.
You might want to look at how swiftz does this – looks like it requires an additional struct.

UDA opCall __traits

This code fails at the second unittest at the getA!B() call. The error is: "need 'this' for 'value' of type 'string'"
The question is. How do I get getA to always return a A, whether the UDA is a type or an opCall?
static A opCall(T...)(T args) {
A ret;
ret.value = args[0];
return ret;
}
string value;
}
#A struct B {
}
#A("hello") struct C {
}
A getA(T)() {
foreach(it; __traits(getAttributes, T)) {
if(is(typeof(it) == A)) {
A ret;
ret.value = it.value;
return ret;
}
}
assert(false);
}
unittest {
A a = getA!C();
assert(a.value == "hello");
}
unittest {
A a = getA!B();
assert(a.value == "");
}
As you know, traits are evaluated at compile-time. So any introspection on values obtained via __traits must be done statically. Luckily D has the "static if condition" for this.
If you change
if(is(typeof(it) == A)) {
to
static if (is(typeof(it) == A)) {
you should not have problems compiling the code as is(typeof(it) == A can be evaluated at compile-time.

haxe "should be int" error

Haxe seems to assume that certain things must be Int. In the following function,
class Main {
static function main() {
function mult_s<T,A>(s:T,x:A):A { return cast s*x; }
var bb = mult_s(1.1,2.2);
}
}
I got (with Haxe 3.01):
Main.hx:xx: characters 48-49 : mult_s.T should be Int
Main.hx:xx: characters 50-51 : mult_s.A should be Int
Can anyone please explain why T and A should be Int instead of Float?
A more puzzling example is this:
class Main {
public static function min<T:(Int,Float)>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //compile error
var b = min(1,2); //ok
}
}
I can't see why t<t2 implies that either t or t2 is Int. But Haxe seems prefer Int: min is fine if called with Int's but fails if called with Float's. Is this reasonable?
Thanks,
min<T:(Int,Float)> means T should be both Int and Float. See the constraints section of Haxe Manual.
Given Int can be converted to Float implicitly, you can safely remove the constraint of Int. i.e. the following will works:
http://try.haxe.org/#420bC
class Test {
public static function min<T:Float>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //ok
$type(a); //Float
trace(a); //1.1
var b = min(1,2); //ok
$type(b); //Int
trace(b); //1
}
}

How to implement Haskell *Maybe* construct in D?

I want to implement Maybe from Haskell in D, just for the hell of it.
This is what I've got so far, but it's not that great. Any ideas how to improve it?
class Maybe(a = int){ } //problem 1: works only with ints
class Just(alias a) : Maybe!(typeof(a)){ }
class Nothing : Maybe!(){ }
Maybe!int doSomething(in int k){
if(k < 10)
return new Just!3; //problem 2: can't say 'Just!k'
else
return new Nothing;
}
Haskell Maybe definition:
data Maybe a = Nothing | Just a
what if you use this
class Maybe(T){ }
class Just(T) : Maybe!(T){
T t;
this(T t){
this.t = t;
}
}
class Nothing : Maybe!(){ }
Maybe!int doSomething(in int k){
if(k < 10)
return new Just!int(3);
else
return new Nothing;
}
personally I'd use tagged union and structs though (and enforce it's a Just when getting the value)
Look at std.typecons.Nullable. It's not exactly the same as Maybe in Haskell, but it's a type which optionally holds a value of whatever type it's instantiated with. So, effectively, it's like Haskell's Maybe, though syntactically, it's a bit different. The source is here if you want to look at it.
I haven't used the Maybe library, but something like this seems to fit the bill:
import std.stdio;
struct Maybe(T)
{
private {
bool isNothing = true;
T value;
}
void opAssign(T val)
{
isNothing = false;
value = val;
}
void opAssign(Maybe!T val)
{
isNothing = val.isNothing;
value = val.value;
}
T get() #property
{
if (!isNothing)
return value;
else
throw new Exception("This is nothing!");
}
bool hasValue() #property
{
return !isNothing;
}
}
Maybe!int doSomething(in int k)
{
Maybe!int ret;
if (k < 10)
ret = 3;
return ret;
}
void main()
{
auto retVal = doSomething(5);
assert(retVal.hasValue);
writeln(retVal.get);
retVal = doSomething(15);
assert(!retVal.hasValue);
writeln(retVal.hasValue);
}
With some creative operator overloading, the Maybe struct could behave quite naturally. Additionally, I've templated the Maybe struct, so it can be used with any type.

Resources