Are these two definitions equivalent?
type
PersonObj = object
name: string
age: int
PersonRef = ref PersonObj
type
PersonObj = ref object
name: string
age: int
In the latter should PersonObj be simply called Person?
They are not equivalent as the first PersonObj is not ref, while the second is. To be equivalent the second definition should read as
type PersonRef = ref object
name: string
age: int
Now Obj or Ref suffixes is your own decision. Usually the suffixes are not used if the type is intended to be always used either as value type or a ref type, so it would be just:
type Person = ref object
name: string
age int
Related
I have a ref object type and would like to iterate over all of its fields and echo them out.
Here an example of what I want:
type Creature* = ref object
s1*: string
s2*: Option[string]
n1*: int
n2*: Option[int]
n3*: int64
n4*: Option[int64]
f1*: float
f2*: Option[float]
b1*: bool
b2*: Option[bool]
var x = Creature(s1: "s1", s2: some("s2"), n1: 1, n2: some(1), n3: 2, n4: some(2.int64), f1: 3.0, f2: some(3.0), b1: true, b2: some(true))
for fieldName, fieldValue in x.fieldPairs:
echo fieldName
However, doing so causes this compiler error:
Error: type mismatch: got <Creature>
but expected one of:
iterator fieldPairs[S: tuple | object; T: tuple | object](x: S; y: T): tuple[
key: string, a, b: RootObj]
first type mismatch at position: 1
required type for x: S: tuple or object
but expression 'x' is of type: Creature
iterator fieldPairs[T: tuple | object](x: T): tuple[key: string, val: RootObj]
first type mismatch at position: 1
required type for x: T: tuple or object
but expression 'x' is of type: Creature
expression: fieldPairs(x)
Going through the documentation, there appear to be no iterators for ref object types, only for object types. If that's the case, then how do you iterate over ref object types?
If you want to use iterators, you need to de-reference the ref-type that you want to iterate over! This may also apply to any other proc that expects an object parameter, but that you want to use with a ref object instance.
In nim, the de-referencing operator is [].
So in order to work, the instance x of the ref object type Creature needs to be de-referenced before iterating over it:
for fieldName, fieldValue in x[].fieldPairs:
echo fieldName
This will also work with any proc you write, for example like this:
proc echoIter(val: object) =
for fieldName, fieldValue in val.fieldPairs:
echo fieldName
echoIter(x[])
It's possible to manually convert seq[Child] to seq[Parent] but maybe there's a better option?
type
ParentRef = ref object of RootObj
a: int
ChildRef = ref object of ParentRef
b: int
let parents = #[ParentRef()]
let children = #[ChildRef()]
proc process(list: seq[ParentRef]): void = discard list
process(parents)
process(children) # <== error
Nim has a stronger type system than many, by default it only implicitly converts types according to these rules.
We can see there that a sub-class is convertible to its superclass,
but seq[type1] is only convertible to seq[type2] if type1==type2, i.e. they are identical, not subtypes.
To add another implicit conversion relationship, one defines a type-converter, either case by case:
converter seqChildToSeqParent(c:seq[ChildRef]):seq[ParentRef]= c.mapIt(it.ParentRef)
or generically for any subtype:
converter toSeqParent[T:ParentRef](x:seq[T]):seq[ParentRef]= x.mapIt(it.ParentRef)
With one of those converters defined, the compiler will convert for you automatically, and call to process(children) will compile and run.
Maybe the better option is to use a generic proc?
type
Parent = object of RootObj
a: int
Child = object of Parent
b: int
let parents = #[Parent(a: 2)]
let children = #[Child(a: 3, b: 5)]
proc process[T: Parent](list: seq[T]): void =
echo repr(list)
echo "Accessing generic attribute a: ", list[0].a
process(parents)
process(children)
In fact, if you don't add the T : Parent restriction that proc will work for anything as long as the compiler finds all the fields it wants on the type:
type
Parent = object of RootObj
a: int
Child = object of Parent
b: int
FooBar = object of RootObj
a: int
bar: string
let parents = #[Parent(a: 2)]
let children = #[Child(a: 3, b: 5)]
let foobars = #[FooBar(a: 42, bar: "Yohoo")]
proc process[T](list: seq[T]): void =
echo repr(list)
echo "Accessing generic attribute a: ", list[0].a
process(parents)
process(children)
process(foobars)
I want to access the string value of a string literal type, similar to typeof operator in C#, otherwise I must define it twice...
myStringLiteral: 'STRING TYPE';
myString:string = typeof(myStringLiteral); // Want myString = 'STRING TYPE'...
Or, if the opposite is possible:
const myString:string = 'STRING TYPE';
myStringLiteral: myString;
You have to not use an explicit type annotation to let the compiler infer the string literal type for the constant (or manually specify the string literal type not string).
If you have the myString constant typed correctly, you can just use typeof to get the type of the constant in a type annotation or type definitions:
const myString = 'STRING TYPE'; // typed as 'STRING TYPE'
type myStringLiteral = typeof myString; // myStringLiteral is 'STRING TYPE'
let otherVar: typeof myString;
package main
import "fmt"
type TT struct {
a int
b float32
c string
}
func (t *TT) String() string {
return fmt.Sprintf("%+v", *t)
}
func main() {
tt := &TT{3, 4, "5"}
fmt.Printf(tt.String())
}
The code can work well. But if I change the String method as in the following, it will cause dead loop. The difference is that the *t is replaced with t. Why?
func (t *TT) String() string {
return fmt.Sprintf("%+v", t)
}
Because the fmt package checks if the value being printed has a String() string method (or in other words: if it implements the fmt.Stringer interface), and if so, it will be called to get the string representation of the value.
This is documented in the fmt package doc:
[...] If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
Here:
return fmt.Sprintf("%+v", *t)
You are passing a value *t of type TT to the fmt package. If the TT.String() method has a pointer receiver, then the method set of the type TT does not include the String() method, so the fmt package will not call it (only the method set of *TT includes it).
If you change the receiver to non-pointer type, then the method set of the type TT will include the String() method, so the fmt package will call that, but this is the method we're currently in, so that's an endless "indirect recursion".
Prevention / protection
If for some reason you do need to use the same receiver type as the type of the value you pass to the fmt package, an easy and common way to avoid this / protect from it is to create a new type with the type keyword, and use type conversion on the value being passed:
func (t TT) String() string {
type TT2 TT
return fmt.Sprintf("%+v", TT2(t))
}
Try this on the Go Playground.
But why does this work? Because the type keyword creates a new type, and the new type will have zero methods (it does not "inherit" the methods of the underlying type).
Does this incur some run-time overhead? No. Quoting from Spec: Type declarations:
Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of x and incur a run-time cost. All other conversions only change the type but not the representation of x.
Read more about this here: Does convertion between alias types in Go create copies?
I am trying some simple code, which I found on natashatherobot.com.
var str = "Hello, playground"
let rangeOfHello = Range(start: str.startIndex, end: advance(str.startIndex, 5))
let helloStr = str.substringWithRange(rangeOfHello)
return helloStr
It works fine when I try it in Playgrounds:
But when I try using it in my Xcode project it gives me a compilation error:
Any ideas why this is happening?
In your function declaration you are saying that it returns a void, but you are trying to return a string, You need to add the -> String in the end of your function to match what you are trying to do
your function:
func getStringBetween(startString: String, endString: String) -> ()
shoud be:
func getStringBetween(startString: String, endString: String) -> String
You did not specify the return type of your func:
func getStringBetween(startString: String, endString: String) -> String {
The problem is the method getStringBetween(:endString:), which you defined in your extension for String.
This method does not define a return type (there's no -> Type after the parameter list). Therefore the implicit return type is Void, so your method could be written as:
func getStringBetween(startString: String, endString: String) -> Void
In Swift the type Void is equivalent to an empty tuple ().
The problem is therefore that Swift expects a return type of Void denoted by (), but you're returning a String.
This problem is easily fixed by adding the return type String to the declaration of your method:
func getStringBetween(startString: String, endString: String) -> String
Side Note:
When writing return, without a specification of what is to be returned, Swift automatically returns ().