How do I use a `concept` in Nim? - nim-lang

I'm wondering how to use a "concept" in nim (0.13). I have the following code:
type
T = concept t
t.a is string
T0 = ref object
a: string
T1 = ref object
a: string
q: string
proc echoT(t: T) : void =
echo "hello " & t.a
echoT(T0(a: "T0"))
echoT(T1(a: "T1", q: "q"))
However, the compiler complains on the first call to echoT:
t.nim(21, 6) Error: type mismatch: got (T0)
Shouldn't this work the same as replacing the echoT declaration with:
proc echoT[T](t: T): void = echo "hello " & t.a
(which does compile and run), except that, in the concept version, the constraint
t.a is string is enforced?
How do I get the compiler to recognize the use of a concept?

Your example compiles and works fine for me (Nim 0.13.0). Is it possible you made a typo in your source file?

Related

How to assign object to ref

This code fails to compile:
var s: ref string = nil
s = ref "hi"
echo s
The error is (2, 9) Error: type expected, but got: "hi". I've tried putting ref and ptr in front and back of the string, tried to find some example in the documentation, but failed.
var s: ref string
new(s)
s[] = "hi"
echo s[]
Declare
Allocate new object
Assign to dereferenced string
Echo final string in dereferenced form
Note that echo s[] is needed because ref string does not implement $ operator, and cannot be converted to string by echo.
Not entirely sure why you want to do this. But first you need to create your ref type, then assign the value to a string. Something like this:
var s: ref string = nil
echo s.repr
new s
s[] = "hi"
echo s[]
echo s.repr
Will output something like this:
nil
hi
ref 0x7f7d4bbcf050 --> 0x7f7d4bbd2090"hi"
But as I said, not sure why you'd want this. Strings are already a reference type. As long as you pass them as mutable to a procedure you will be able to modify the underlying data:
var s: string = ""
s = "hi"
echo s
echo s.repr
proc test(x: string) =
echo x.repr
proc testM(x: var string) =
echo x.repr
x[1] = 'o'
test s
testM s
echo s
echo s.repr
Will output something like:
hi
0x7f5fc2807060"hi"
0x7f5fc2807060"hi"
0x7f5fc2807060"hi"
ho
0x7f5fc2807060"ho"

assign an int(eg. 10) to a string member in a struct in c++, why it compile success?

I'm practicing <thinking in c++ > for chapter5, ex01:
Write a struct called Lib that contains three string objects a, b, and c.
In main( ) create a Lib object called x and assign to x.a, x.b, and x.c.
Print out the values.
in the beginning, I'm trying:
// ex02.cpp
#include <iostream>
#include <string>
using namespace std;
struct Lib {
string a;
string b;
string c;
};
int main(){
Lib x;
x.a = 1; // here I forgot the string object, and incorrectly assign the wrong value to x.a
x.b = 2;
x.c = 3;
cout << x.a << " " << x.b << " " << x.c << endl;
return 0;
}
and it can compile successfully, but the run result seems only two blank spaces:
[root#VM-0-2-centos ch05]# g++ ex02.cpp
[root#VM-0-2-centos ch05]# ./a.out
[root#VM-0-2-centos ch05]#
at this time I find the wrong assignment. but why it should not give a compile error?
when I modify the assignment to the follows:
x.a = "hello";
x.b = "world";
x.c = "welcome";
it compiles success, and give the right run result:
[root#VM-0-2-centos ch05]# g++ ex02.cpp
[root#VM-0-2-centos ch05]# ./a.out
hello world welcome
[root#VM-0-2-centos ch05]#
my question is why x.a = 1 can compile success?
and when I try:
string test = 1;
it will compile error:
error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
U need to verify my statement by yourself. To see string code.
First, When u declare Lib x, the member of x (a, b, c) will call string constructor. So when assign value to the member of x (x.a = 1), it will call "=operation".
However, string test = 1, it will call constructor.
the most difference is caller. the type of parameter of string constructor is "const char*", but "=operation" can get other type of parameter. So, x.a = 1 at compile is passing.
Note, "int" will cast to a certain type by default.
Thx, #Muqali He, you give me the hint and direction.
I try to understand the string class from here: https://www.cplusplus.com/reference/string/string/operator=/
And I understand a bit more.
for c++98, when I use "=", there is three overload member function:
when I try:
string t2;
t2 = "test";
it's OK. and I try:
string t3;
t3 = 256;
it will get a warning:
warning: overflow in implicit constant conversion
at this time, 256 will be recognized as a char. when you output this value, it will transform into its ASCII code:
string t4;
t4 = 100;
cout << "t4= " << t4 << endl;
the ouput is
t4 = d
if I try:
string t5 = 100; // it will compile error
because there's no corresponding constructor

Why proc with generic types specified explicitly is not working?

If types for map specified explicitly the example won't compile, why?
This works
import sequtils
let nlist = #[1, 2]
let slist: seq[string] = nlist.map(proc (v: auto): auto = $v)
But this won't:
let slist: seq[string] = nlist.map[int, string](proc (v: auto): auto = $v)
Remember that map is just a normal proc which accepts two parameters, and you happen to be able to use it as first.map(second), due to the method call syntax, but there are some limitations. In fact, if you write that code as a normal proc call:
import sequtils
let nlist = #[1, 2]
let slist: seq[string] = map[int, string](nlist, proc (v: auto): auto = $v)
Then the compiler is not confused any more by the syntax and throws you a proper reason:
Error: A nested proc can have generic parameters only when it is used as an operand to another routine and the types of the generic paramers can be inferred from the expected signature.

How to define type conversion to string for a custom type

Can I define how a conversion to string, using String() would be applied to my custom type myint? And how to do so?
I was expecting to define the method String() to be enough as it is used by fmt.Println() but apparently not by string(). This is purely a theoretical question as I am learning Go and was surprised by this behavior.
Here is an example showing the behavior:
package main
import (
"fmt"
)
type myint int
func (m myint) String() string {
return fmt.Sprintf("%d", m)
}
func main() {
var val myint = 42
mystr := "Testing: " + string(val)
fmt.Println(mystr, val)
}
Which outputs:
Testing: * 42
But I was expecting:
Testing: 42 42
Can I define how a conversion to string, using string() would be applied to my custom type myint? And how to do so?
No, you can't "override" conversion behavior. It's recorded in Spec: Conversions, and that's the end of it. The String() method works for the fmt package because the fmt package is written to explicitly check for the presence of the String() string method. Conversions don't do that.
If you need custom conversion behavior, don't use conversion, but implement your logic in methods (or functions), and call those methods (or functions).
So in your example you would write:
mystr := "Testing: " + val.String()
And you would get your expected output (try it on the Go Playground):
Testing: 42 42

Chance for this hole in Groovy staic typing to be fixed

When I run the following Groovy snippet, it prints ",a,b,c" as expected:
#CompileStatic
public static void main(String[] args) {
def inList = ["a", "b", "c"]
def outList = inList.inject("", { a, b -> a + "," + b })
println(outList)
}
Now I change the first parameter in inject from an empty string to the number 0:
#CompileStatic
public static void main(String[] args) {
def inList = ["a", "b", "c"]
def outList = inList.inject(0, { a, b -> a + "," + b })
println(outList)
}
This won't work an produces an exception "Cannot cast object '0,a' with class 'java.lang.String' to class 'java.lang.Number'". Problem is that the compiler did not complain. I tried this in Scala and Kotlin (where inject is called fold) an the respective compiler complains about the mismatch as expected. Also the counterpart in Java8 does not compile (it says found int, required: java.lang.String):
List<String> list = Arrays.asList("a", "b", "c");
Object obj = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(obj);
Question is now whether this can be fixed in Groovy or whether this is a a general problem because of static typing being introduced later into the language.
I think (I'm not 100% sure) that it is a bug in Groovy, very probably somewhere in type inference, and it can be fixed. Try to fill an issue in the bug tracker.
If you want to see compilation error, you can give types to closure parameters
inList.inject(0, { String a, String b -> a + "," + b })
Gives an error:
Expected parameter of type java.lang.Integer but got java.lang.String
# line 7, column 38.
def outList = inList.inject(0, { String a, String b -> a + "," + b})
^

Resources