standard (idiomatic) way of convert an object to string - dylan

I tried to print an object of this class:
define class <bill> (<object>)
slot num :: <string>;
slot ref :: <string>;
end class <bill>;
I can make a method like say
define method say (bill : <bill>) => ();
format-out("num:%s\n", bill.num);
format-out("ref:%s\n", bill.ref);
end method say;
but I want a method to convert the object to <string> that can be used like
format-out("%s\n", bill);
or
format-out("%s\n", as(<string>, bill));
or
format-out("%=\n", bill);
I tried
define method as(type == <string>, bill :: <bill>)
=> (s :: <string>);
let result :: <stretchy-vector> = make(<stretchy-vector>);
add!(result, bill.num);
add!(result, bill.ref);
join(result, " ");
end method as;
but with:
format-out("\%s\n", as(<string>,bill));
I had this result
Object {<bill>} cannot be converted to class {<class>: <string>}
Object {<bill> 0x1ff8180} cannot be converted to class {class <string> 0x7f5d5c645c00}
Breaking into debugger.
Trace/breakpoint trap
An with this:
format-out("%s\n", bill);
that result:
{<bill> #x00000000025EF1B0}
What I'm doing wrong?
What is the standard (idiomatic) way of printing an object?

The idiomatic way to adding support for printing an object is by specializing print-object. But if you want to be able to convert object representation to string, specializing as generic is the way to go, as you did. It works here, so maybe there's a bug somewhere:
module: bill
define class <bill> (<object>)
constant slot num :: <string>, init-keyword: num:;
constant slot ref :: <string>, init-keyword: ref:
end class <bill>;
define method as(type == <string>, bill :: <bill>) => (s :: <string>);
join(vector(bill.num, bill.ref), " ");
end method as;
format-out("%=\n", as(<string>, make(<bill>, num: "1", ref: "a")));
Result:
$ bill
"1 a"

Related

Why isn't Python NewType compatible with isinstance and type?

This doesn't seem to work:
from typing import NewType
MyStr = NewType("MyStr", str)
x = MyStr("Hello World")
isinstance(x, MyStr)
I don't even get False, but TypeError: isinstance() arg 2 must be a type or tuple of types because MyStr is a function and isinstance wants one or more type.
Even assert type(x) == MyStr or is MyStr fails.
What am I doing wrong?
Cross-reference: inheritance from str or int
Even more detailed in the same question: https://stackoverflow.com/a/2673802/1091677
If you would like to subclass Python's str, you would need to do the following way:
class MyStr(str):
# Class instances construction in Python follows this two-step call:
# First __new__, which allocates the immutable structure,
# Then __init__, to set up the mutable part.
# Since str in python is immutable, it has no __init__ method.
# All data for str must be set at __new__ execution, so instead
# of overriding __init__, we override __new__:
def __new__(cls, *args, **kwargs):
return str.__new__(cls, *args, **kwargs)
Then:
x = MyStr("Hello World")
isinstance(x, MyStr)
returns True as expected
As at python 3.10...
I'd speculate that the answer to
"Why isn't Python NewType compatible with isinstance and type?"
... is "It is a limitation of NewType".
I'd speculate that the answer to
"What am I doing wrong?"
... is "nothing". You are assuming NewType makes a new runtime type, it appears that it doesn't.
And for what it's worth, I wish it did work.
maybe you want a type that is methods like str does but is not a str?
A simple way to get that effect is just:
class MyStr:
value:str
def __init__(self,value:str):
self.value=value
pass
... but that means using all the string methods is "manual", e.g.
x=MyStr('fred')
x.value.startswith('fr')
... you could use #dataclass to add compare etc.
This is not a one-size-fits-all answer, but it might suit your application.
then make that simple
class MyStr:
value:str
def __init__(self,value:str):
self.value=value
...generic like Str in (incomplete) https://github.com/urnest/urnest/blob/master/xju/newtype.py
... and you can write:
class MyStrType:pass; class MyOtherStrType:pass
class MyStr(Str[MyStrType]):
pass
class MyOtherStr(Str[MyOtherStrType]):
pass
x=MyStr('fred')
y=MyOtherStr('fred')
x < y # ! mypy error distinct types MyStr and MyOtherStr
That's what I was after, which might be what you were after? I have to provide Int,Str separately but in my experience distinct int, str, float, bool, bytes types give a lot of readability and error-rejection leverage. I will add Float, Bool, Bytes to xju.newtype soon and give them all the full set of methods.
looks might have been "fixed" in python 3.10:
https://docs.python.org/3/library/typing.html?highlight=typing#newtype
says:
Changed in version 3.10: NewType is now a class rather than a function. There is some additional runtime cost when calling NewType over a regular function. However, this cost will be reduced in 3.11.0.
I don't have 3.10 handy as I write this to try your example.

HP-UFT / VBscript - Setting an array value through a function with an array index reference

I have an issue with assigning/retrieving correct values to/from an array which is within a class in VBScript. Whenever I try to set the array's value through a stand-alone function, it just does not work and I keep getting the old array values.
Here is an example code:
Class NewClass
Public TestValues
Public Sub Init()
TestValues = array("value0", "value1", "value2")
End Sub
End Class
Class NewFunctions
Public Function GetValue(xRef)
GetValue = xRef(2)
print "Value within Function: " & xRef(2)
End Function
Public Sub SetValue(xRef, xValue)
xRef(2) = xValue
print "Value within Sub: " & xRef(2)
End Sub
End Class
Dim MyClass, MyFunction
Set MyClass = New NewClass
Set MyFunction = New NewFunctions
Now, when I try to set the index 2 of the given array MyClass.TestValues with the SetValue Sub, it claims the new value has been set, but when I then call GetValue for this array or print out the content of the MyClass.TestValues(2) directly, I am still getting the old values:
MyFunction.SetValue MyClass.TestValues, "newvalue2"
It returns: Value within Sub: newvalue2
But when I retrieve the value with GetValue:
MyFunction.GetValue MyClass.TestValues
It returns: Value within Function: value2, which is the old value.
When I, however, set the array directly:
Myclass.TestValues(2) = "newvalue2"
then calling with:
MyFunction.GetValue MyClass.TestValues
gives me correct result: Value within Function: newvalue2
I am not sure whether this is a general VBScript behavior and I am making a mistake in hoping to change array values in this 'dirty' manner or whether this is strictly HP-UFT (Unified Functional Testing) related, since this is where I could observe this.
I am not a profficient VBScripter either so I appreciate any help.
This is a documented behaviour
Argument in a Class
If the parameter is specified as ByRef, the argument is passed by
value if the variable sent as an argument is in a class

How do I use [TypeArguments] with a constructor reference in Java 8?

Section 15.13 of the Java Language Specification for Java 8 describes this form of the method reference syntax for creating a constructor reference:
ClassType :: [TypeArguments] new
For example:
String s = "abc";
UnaryOperator<String> test0 = String::new; // String(String) constructor.
String s0 = test0.apply(s);
System.out.println("s0 = " + s0); // Prints "abc".
char[] chars = {'x','y','z'};
Function<char[], String> test1 = String::new; // String(char[]) constructor.
String s1 = test1.apply(chars);
System.out.println("s1 = " + s1); // Prints "xyz"
That all works fine, but it seems that absolutely anything (excluding primitives) can be also supplied for the [TypeArguments] and everything still works:
Here's a silly example to prove the point:
Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
String s2 = test2.apply("123");
System.out.println("s2 = " + s2); // Prints "123"
A few questions arising:
[1] Since the String class doesn't even use generics, is it valid that the compiler allows the creation of that test2 constructor reference with those meaningless [TypeArguments]?
[2] What would be a meaningful example of using [TypeArguments] when creating a constructor reference?
[3] Under what conditions is it essential to specify [TypeArguments] when creating a constructor reference?
1 15.13.1. Compile-Time Declaration of a Method Reference
If the method reference expression has the form ClassType :: [TypeArguments] new, the potentially applicable methods are a set of notional methods corresponding to the constructors of ClassType.
...
Otherwise, the candidate notional member methods are the constructors of ClassType, treated as if they were methods with return type ClassType. Among these candidates, the methods with appropriate accessibility, arity (n), and type argument arity (derived from [TypeArguments]) are selected, as specified in §15.12.2.1.
JLS 15.12.2.1. Identify Potentially Applicable Methods
This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.
2 Whenever a constructor is parameterized. I've never stumbled upon one.
public class Foo {
public <T> Foo(T parameter) {
...
Function<String, Foo> test = Foo::<String>new
3 When the compiler can't infer the type.

How to apply transformations/filters on Lift Record Field before writing/reading its value

I'm using Lift Record persistence and I want to apply some transformations on a Field whenever I set or get its value. For instance, for StringField I want to set it to lower case automatically in Record object.
object someField extends StringField(this, 64) {
...
// how do I apply transformations here?
...
}
In Lift Mapper there is a method setFilter which does exactly that, but I can't find its equivalent in Record. In Mapper it looks like this:
object someField extends MappedString(this, 64) {
...
override def setFilter = trim _ :: toUpper _ :: super.setFilter
...
}
Couple options I'm considering are:
override set method, but there are many of them, I'm afraid to incompletely override subset of required methods, so I can't envision consequences. :)
using lifecycle callbacks - seems like overkill.
Any help is appreciated. Thanks ;)
Credit goes to #jcern for pointing this out:
Record has method def setFilter: List[(ValueType) ⇒ ValueType] which is very similar to def setFilter: List[(FieldType) ⇒ FieldType].
It is used the same way, i.e. filter will be applied when setting or querying values. Here is a quick example:
class Tag extends MongoRecord[Tag] with ObjectIdPk[Tag] {
...
object name extends StringField(this, 32) {
override def setFilter = trim _ :: toLower _ :: super.setFilter
}
...
}
Tag.createRecord.name("UPPER")
// lowercases tag name:
//res1: Tag = class Tag={name=upper, _id=521bb306e4b04eacd74dd217}

How should I handle a template string in Xtext?

I have the following input:
a: "a is {Foo foo}"
where foo is of type Foo; the business layer will eventually provide a value for the variable. After processing the input, two files will be generated: A properties file and a Java class:
a=a is {0}
public static I18nMessage a( Foo foo ) {
return new I18nMessageBuilder().id( "a" ).args( foo ).build();
}
The idea is that I assign each message an id which gives me a Java class that contains methods (where name == id) and which accepts typed parameters to complete the messages.
My question: How should I handle the text strings in my Xtext grammar? I would like to have code completion for the parameter types (Foo) but I have no idea how to handle the rest of the string which can contain spaces and any valid Unicode character.
Suggestions?
I found a better solution which gives a pretty simple grammar and solves some other problems:
a(Foo foo): "a is " foo;
So the text message is a list of strings and parameters. This way, code completion is very simple and there is no need for escape sequences if you want to add formatters:
a(Date d): "Date is " d( "short" );

Resources