The difference between t and *t - string

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?

Related

What is the Rust equivalent of Scala's value classes?

Scala's value classes provide a way to use the type system without allocating runtime objects (structs in case of Rust). I'm looking for an equivalent in Rust.
The use case I'd like to cover is passing around a string that represents a URI, by annotating relevant signatures with something like Uri instead of String, and, ideally, use this Uri when a String is expected. All this with minimal overhead.
An obvious solution would be to use structs with one field:
struct Uri { val: String }
This has the drawback of slightly awkward usage, not being acceptable where a String is expected, and I'm unsure of its overhead.
Is there something similar to Scala's value classes in Rust? Is there some other mechanism that facilitates this use case?
I believe the thing you are looking for is the "strong type system". In Rust it is represented with a tuple struct with one field (a newtype):
struct Uri(pub String);
This creates a strong type with the least overhead. I'd say this just creates a mark for the compiler that this type is Uri and nothing else. Since this is a strong type, you can't simply pass String to it and get a String from it, you must do a conversion manually.
Simple example gives you a strong type on top of the String:
struct Uri(pub String);
fn takes_uri(uri: Uri) {
println!("URI: {}", uri.0);
}
fn takes_string(uri: String) {
println!("String: {}", uri);
}
fn main() {
let uri = Uri("https://stackoverflow.com".to_owned());
takes_uri(uri);
// takes_string(uri); // This does not compile
}
The key thing with strong types is that you can not implicitly cast them so this requires the code writer to write explicit code.

Golang String method for interface type

I am solving the problems for the book The Go Programming Language,
and in exercise 7.13 it is required to add a String method to an interface.
Is this possible to add a String() method to an interface? Because the data type is not known until runtime.
Adding a method to an interface just means to include that method in the method set defined by the interface type.
For example this is an interface:
type Fooer interface {
Foo()
}
It has one method: Foo(). To add the String() method to this interface:
type Fooer interface {
Foo()
String() string
}
Done. We have added the String() method to this interface.
This has the consequence that if a concrete type wants to implement this Fooer interface, previously it was enough to have just a Foo() method. Now it also has to have a String() method.
Also note that in Go implementing interfaces is implicit. There is no declaration of intent. A type implicitly satisfies an interface if it has all the methods of the interface.
A concrete type may or may not have a String() method, independently from our Fooer interface. The concrete type may not even know about our Fooer interface, and it doesn't need to.
Here's a concrete type implementating this Fooer interface:
type fooerImpl int
func (f fooerImpl) Foo() {
fmt.Printf("Foo() called, I'm %d\n", int(f))
}
func (f fooerImpl) String() string {
return fmt.Sprintf("Foo[%d]", int(f))
}
Testing it:
var f Fooer = fooerImpl(3)
f.Foo()
fmt.Println(f.String())
fmt.Println(f)
Output (try it on the Go Playground):
Foo() called, I'm 3
Foo[3]
Foo[3]
Consequences of adding a method to an interface
If you arbitrarily add a new method to an interface, it may cause certain existing concrete types which previously implemented the interface to not implement it anymore (due to lack of the newly added method).
If these existing concrete types were used as instances of the interface, they will cause a compile-time error and will not work until you add the missing new method. For example if we remove the fooerImpl.String() method from the above example, the code var f Fooer = fooerImpl(3) results in compile-time error:
cannot use fooerImpl(3) (type fooerImpl) as type Fooer in assignment:
fooerImpl does not implement Fooer (missing String method)
If the existing concrete types were not used as instances of the interface directly, but e.g. they were passed around wrapped in the empty interface interface{} and type assertion was used to extract a value of the interface, those type assertions will not hold anymore. The "simple" form of type assertion x.(T) will result in a runtime panic, the special form v, ok := x.(T) will return nil and false.
For example using the above fooerImpl type without the String() method:
var f0 interface{} = fooerImpl(3)
f := f0.(Fooer)
Results in runtime panic:
panic: interface conversion: main.fooerImpl is not main.Fooer: missing method String
And using the special form of type conversion:
if f, ok := f0.(Fooer); ok {
f.Foo()
} else {
fmt.Println("Not instance of Fooer!", f)
}
Results in:
Not instance of Fooer! <nil>
If by any chance the existing concrete type already had a method which you have just added to the interface and it has the same signature (same parameter and return types), then that's cool, the concrete type will "continue" to implement the new interface too. If the signatures do not match (e.g. the existing method has different return type), then it will not satisfy the interface and it's the same as not having a method with the same name.

Does a struct implement all the interfaces that one of their embedded type implement?

I have this example
// embed project main.go
package main
import (
"fmt"
)
type A struct {
A1 int
A2 int
}
func (a A) Incr() int {
a.A1++
return a.A1
}
type B struct {
A
D int
}
type C interface {
Incr() int
}
func Add(c C) {
d := c.Incr()
fmt.Println(d)
}
func main() {
var s B
s.Incr() //B has Incr
Add(s)
}
Using this example i wanted to check whether B implement interface C or not. In this example Add accept s (type B) as input. B implement C.
But when i change Incr() method from original to
func (a *A) Incr() int {
a.A1++
return a.A1
}
It compiler gives the error
./main.go:35: cannot use s (type B) as type C in argument to
AddContent: B does not implement C (Incr method has pointer receiver)
So i am still confused whether a struct implement all the interface that one of their embedded type implement.
Yes, your struct implements the method set of the embedded type.
However, when you change the signature of Incr to func (a *A) Incr() int, you need a pointer for the receiver of that method. A itself doesn't implement Incr when it has a pointer receiver.
The reason the s.Incr() call works, is that the s value is addressable, and Go automatically references it for the method call. When you pass s to Add, you're attempting to convert it to a C interface, the value would no longer be addressable, and the Incr method isn't in the method set.
In this case, you can either change the embedded type to *A,
type B struct {
*A
D int
}
take the address of s at the call site
Add(&s)
or make s a pointer (*B):
s := &B{}
Add(s)
The relevent portion of the spec
Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also
includes promoted methods with receiver *T.
If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an anonymous field *T, the method sets of S and *S both include
promoted methods with receiver T or *T.
B embedded A, so method sets of B include protomoted methods with receiver A, but does not include *A

In Go, why isn't the stringer interface used when casting to string?

package main
type foo struct {
bar string
baz string
}
func (f foo) String() string {
return f.bar + " " + f.baz
}
func main() {
f := foo{"hello", "world"}
v := string(f)
}
This outputs main.go:14: cannot convert f (type foo) to type string.
So it would seem that casting something to a string does not look at the stinger interface. My guess is that this is because casting is implemented on a lower level than the stringer interface and it's impossible/hard to mix the two, but I'm not sure. Can anyone shed any light on this?
Also, since this is not possible, what would be idiomatic way to convert my struct to a string in this case? Do I just call .String() myself, or fmt.Sprintf("%s", f), or something else?
There is no casting in Go, there is type Conversion and Type assertion.
What you're doing (T(Expression)) is a conversion and it has strict rules when it can be used and what the result will be.
There are specific rules applied to Conversions to and from a string type. So what you want cannot be achieved with type conversion.
The simplest and preferred way would be to call the method yourself:
v := f.String()
fmt.Sprintf() would be just an unnecessary overhead and complication if your struct already implements Stringer. But if you don't have guarantee for this, then yes, fmt.Sprintf() would be the general way.
You could ask why?
In the specification level the type conversion expression is not defined as the result of a custom/user made function or method. The Stringer interface (type Stringer interface{String() string}) is not even a built-in type in contrast to the error interface.
But despite the fact that Stringer is not a built-in type, it is still present in some packages (for example in fmt.Stringer) and is checked by various methods or functions (e.g. fmt.Printf() and relatives).

Does Rust have a type or trait that all entities "inherit" or implement?

In Java, all objects inherit from java.lang.Object. In Go, all types/structs implement the empty interface interface {}. Is there any similar construct in the Rust language?
If the answer is no, what makes it unnecessary? Is it because all entities in Rust (except modules) can be parameterized by type? Does that remove the need for a common "supertype" or common Trait shared by all Rust entities/structs/enums?
Yes, there is a trait. It is std::any::Any.
From the docs:
The Any trait is implemented by all 'static types, and can be used for dynamic typing
The way I understand it, if not completely unnecessary, it is less necessary in Rust to have a base type.
Note that the introduction of parametric polymorphism (generics) has removed most of the use cases for Object also in java.
With Object you can implement a "generic" method that can work with any kind of java type. On the other hand, when you have an Object you can't do much with it... You have to cast it back to the actual subtype to use it.
For instance, the old non-generic version of java collections worked with Objects, This means you had to work like this (sample is straight from this post on Oracle's site):
LinkedList list = new LinkedList();
list.add(new Integer(1));
Integer num = (Integer) list.get(0);
add takes an Object (so you can use the collection with any type). But get returns an Object too, so you have to cast it back to Integer based on the knowledge that you (the programmer) have on what you originally inserted in the LinkedList. There's very little type safety here.
The new generic version of the same container, since java 1.5, is:
LinkedList<Integer> list = new LinkedList<Integer>();
list.add(new Integer(1));
Integer num = list.get(0);
Now you have a list of Integer, so add takes Integer and get returns Integer. Object is nowhere to be seen any more (although due to type erasure it's just there, barely hiding under the hood...)
Note that Go's main use of interface{} stems from the fact that Go does not have generics. The main pattern of use for interface{} is roughly the same. You use it when you have to work with multiple types and you sort-of cast it (although in a safer way and with a more elegant pattern) back to a more useful type before using it.
With that in mind, you could theoretically use Any in Rust in the same way (checking actual type and casting to it before using it). It's just that you will likely not find many cases where this might be useful.
The code below works on rustc 0.13-nightly (2015-01-01), although I'm sure there are better ways to write it...
use std::any::{Any, AnyRefExt};
// just a couple of random types
struct Foo {
a: f64
}
enum Bar {
Baz(int),
Qux
}
fn main() {
// create an array of things that could have any type
let anything = &[&1i as &Any, &Foo{a: 2.} as &Any, &Bar::Qux as &Any];
// iterate and print only the integer
for &any in anything.iter() {
if any.is::<int>() { // check if type is int
match any.downcast_ref::<int>() { // cast to int
Some(a) => { println!("{}", *a); }
None => panic!()
}
// or just (shorter version of the match)
println!("{}", *any.downcast_ref::<int>().unwrap());
}
}
}

Resources