How to multiply strings in Haxe - string

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.

Related

Flutter compute function not called if parameter is not a primitive?

I tried to send a Map to a compute, but computer is never called. The strange point is if I replace Map with int, it works:
void A()
{
var map=Map();
map["p1"]=90;
D("before compute");
var r1 = await compute(p1, 10);
D("after compute(p1) : $r1");
var r2 = await compute(p2, map);
// code never reaches here!
D("after compute(p2) : $r2");
}
static int p2(Map p)
{
return p["p1"]*10;
}
static int p1(int z)
{
return z*10;
}
output is :
after compute(p1) : 100
Flutter compute methods use Isolates and its only transfer (null, num, bool, double, String) types.
https://api.flutter.dev/flutter/dart-isolate/SendPort/send.html
Just define exact type of Map that "p2" receives as parameter:
static int p2(Map<String,int> p)
{
return p["p1"]*10;
}
Try passing a const parameter:
var r2 = await compute(p2, {"p1":90});

Create new this on method call

This may be a stupid question, but is it possible to create a new this on a method call of a class?
E.g:
const foo = new Foo();
console.log(foo.a(1).b(2));
// for example, outputs 3 (1+2)
// the a method will create a new namespace and attach 1 to it, and b will use that new namespace
console.log(foo.b(2));
// this will result in an error, as there is no new namespace from the a method anymore, so b cannot add to anything?
Maybe this is too hard to understand, sorry.
class Foo {
a(number) {
this.a = number;
return this;
}
b(number) {
return this.a + number;
}
}
This would be the code where it uses the same this variable - this doesn't fit what I wanted but is what I currently have.
// pseudo
class Foo {
a(number) {
const uniqueVariable = number
return uniqueVariable
// it'll somehow pass the number from this method to the next method
}
// where it can be used with the second method's input
b(uniqueVariable, number) {
return uniqueVariable + number
}
}
foo.a(1).b(2) = 3
This example would obviously cause an error because the return value of a() a number, not something to use a method on again.
Please let me know if I need to explain further -- I'm having some struggle explaining it properly.
If the intention is that foo.a(1).b(2) changes foo, or if you don't mind changing foo, the other answers here work.
But if you only want foo.a(1).b(2) to return 3 without modifying foo, then you need to return a new Foo.
Now, if you really hell bent on having console.log() print 3 rather than something like Foo { value: 3 }, you can also customize inspect() (given that the question is tagged with node.js).
All together:
const util = require('util');
class Foo {
constructor(value) {
this.value = value || 0;
}
add(value) {
return new Foo(this.value + value);
}
a(value) {
return this.add(value);
}
b(value) {
return this.add(value);
}
[util.inspect.custom]() {
return this.value;
}
}
const foo = new Foo();
console.log(foo);
console.log(foo.a(2).b(1));
console.log(foo);
Output:
0
3
0
On my solution, I decided to create two variables to hold the values of each method. (https://jsbin.com/wozuyefebu/edit?js,console)
The a() method will return a number if the isSingle parameter is set to true. If not, it will return the this object, allowing you to chain the b() method. This is might be a hack but I believe it solves your problem.
I write about Javascript and web development on my blog :) https://changani.me/blog
class Foo {
constructor() {
this.aValue = 0;
this.bValue = 0;
}
/**
* #param {Number} value
* #param {Boolean} isSingle
* #returns {Object/Number}
*/
a(value = 0, isSingle = false) {
this.aValue = value;
return isSingle ? this.aValue : this;
}
/**
* #param {Number} value
* #returns {Number}
*/
b(value = 0) {
this.bValue = this.aValue + value;
return this.bValue;
}
}
const x = new Foo();
console.log("Should return 3: ", x.a(2).b(1));
console.log("Should return an 2: ", x.a(2, true));
console.log("Should return an instance of the object: ", x.a(2));
console.log("Should return 1: ", x.b(1));
console.log("Should return 0: ", x.a().b());
(https://jsbin.com/wozuyefebu/edit?js,console)
If you want to be able to invoke methods on return value of methods, then, you should return this from those methods. However, you will need an additional method, say value() to actuall get the result of sum.
A possible way is show below.
class Foo {
_a = 0;
_b = 0;
a(number) {
this._a = number;
return this;
}
b(number) {
this._b = number;
return this;
}
value() {
return this._a + this._b;
}
}
const foo = new Foo();
console.log(foo.a(1).b(2).value());
console.log(foo.b(5).value());

Generic Template String like in Python in Dart

In python, I often use strings as templates, e.g.
templateUrl = '{host}/api/v3/{container}/{resourceid}'
params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
api.get(templateUrl.format(**params))
This allows for easy base class setup and the like. How can I do the same in dart?
I'm assuming I will need to create a utility function to parse the template and substitute manually but really hoping there is something ready to use.
Perhaps a TemplateString class with a format method that takes a Map of name/value pairs to substitute into the string.
Note: the objective is to have a generic "format" or "interpolation" function that doesn't need to know in advance what tags or names will exist in the template.
Further clarification: the templates themselves are not resolved when they are set up. Specifically, the template is defined in one place in the code and then used in many other places.
Dart does not have a generic template string functionality that would allow you to insert values into your template at runtime.
Dart only allows you to interpolate strings with variables using the $ syntax in strings, e.g. var string = '$domain/api/v3/${actions.get}'. You would need to have all the variables defined in your code beforehand.
However, you can easily create your own implementation.
Implementation
You pretty much explained how to do it in your question yourself: you pass a map and use it to have generic access to the parameters using the [] operator.
To convert the template string into something that is easy to access, I would simply create another List containing fixed components, like /api/v3/ and another Map that holds generic components with their name and their position in the template string.
class TemplateString {
final List<String> fixedComponents;
final Map<int, String> genericComponents;
int totalComponents;
TemplateString(String template)
: fixedComponents = <String>[],
genericComponents = <int, String>{},
totalComponents = 0 {
final List<String> components = template.split('{');
for (String component in components) {
if (component == '') continue; // If the template starts with "{", skip the first element.
final split = component.split('}');
if (split.length != 1) {
// The condition allows for template strings without parameters.
genericComponents[totalComponents] = split.first;
totalComponents++;
}
if (split.last != '') {
fixedComponents.add(split.last);
totalComponents++;
}
}
}
String format(Map<String, dynamic> params) {
String result = '';
int fixedComponent = 0;
for (int i = 0; i < totalComponents; i++) {
if (genericComponents.containsKey(i)) {
result += '${params[genericComponents[i]]}';
continue;
}
result += fixedComponents[fixedComponent++];
}
return result;
}
}
Here would be an example usage, I hope that the result is what you expected:
main() {
final templateUrl = TemplateString('{host}/api/v3/{container}/{resourceid}');
final params = <String, dynamic>{'host': 'www.api.com', 'container': 'books', 'resourceid': 10};
print(templateUrl.format(params)); // www.api.com/api/v3/books/10
}
Here it is as a Gist.
Here is my solution:
extension StringFormating on String {
String format(List<String> values) {
int index = 0;
return replaceAllMapped(new RegExp(r'{.*?}'), (_) {
final value = values[index];
index++;
return value;
});
}
String formatWithMap(Map<String, String> mappedValues) {
return replaceAllMapped(new RegExp(r'{(.*?)}'), (match) {
final mapped = mappedValues[match[1]];
if (mapped == null)
throw ArgumentError(
'$mappedValues does not contain the key "${match[1]}"');
return mapped;
});
}
}
This gives you a very similar functionality to what python offers:
"Test {} with {}!".format(["it", "foo"]);
"Test {a} with {b}!".formatWithMap({"a": "it", "b": "foo"})
both return "Test it with foo!"
It's even more easy in Dart. Sample code below :
String host = "www.api.com"
String container = "books"
int resourceId = 10
String templateUrl = "$host/api/v3/$container/${resourceId.toString()}"
With the map, you can do as follows :
Map<String, String> params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
String templateUrl = "${params['host']}/api/v3/${params['container']}/${params['resourceId']}"
Note : The above code defines Map as <String, String>. You might want <String, Dynamic> (and use .toString())
Wouldn't it be simplest to just make it a function with named arguments? You could add some input validation if you wanted to.
String templateUrl({String host = "", String container = "", int resourceid = 0 }) {
return "$host/api/v3/$container/$resourceId";
}
void main() {
api.get(templateUrl(host:"www.api.com", container:"books", resourceid:10));
}

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
}
}

Do we have to return value at setter?

In haxe documentation of properties, there is the example:
class C {
public var x(get,set) : Int;
function get_x(){ return 123; }
function set_x(value){
doSomethingWith(value);
return 123;
}
}
But why do we have to return a value in setter of x above? is there a good reason?
The reason is, in Haxe, the assignment expression does return a value, eg.
var a;
trace(a = 3.14);//3.14
It is natural since we can chain assignments together:
var test = a = 3.14; //test will be 3.14
For example there is a weird class,
class Weird {
public function new():Void {}
public var x(get, set):Int;
function get_x() return x;
function set_x(v:Int):Int {
x = v;
return 123;
}
}
var weird = new Weird();
trace(weird.x = 456); //123
trace(weird.x); //456
var test = weird.x = 456; //test will be 123
But of course, usually we simply return the input of the setter, because it is more logical:
function set_x(v:Int):Int {
return x = v;
}
Sometimes it's just nice to have a setter function return the previous value, so you can code like this:
oldval=set(newval);
do_something();
set(oldval);
to temporarily set a new value, then restore the old one after you've finished.

Resources