Rust version of Python's __getitem__ - rust

Python has a special class method __getitem__ that is basically syntactic sugar. For example,
class MyList:
def __init__(self):
self.list = []
def __getitem__(self, key):
return self.list[key]
will allow you to get elements of MyList objects like this: mylist[2]. I wonder if there is a trait in Rust that does the same kind of thing. Just like the trait Ord in Rust allows you to use >, <, ==.

You can implement Index for your struct, which allows you to use the bracket operators to get an immutable reference to the data. If you want mutable access, you also need IndexMut

Related

How to refer the struct itself in Julia

I have this code:
struct MyStruct
text::String
function MyStruct(_text::String)
text = _text
# do other things
end
end
When I wrote this, I realized that Julia is not recognizing text as MyStruct's field. How can I do something like this in Julia like in Python?
self.text = _text
Don't try to imitate Python. Julia is not object oriented.
You could emulate a Python-style constructor by
mutable struct MyStruct
text::String
function MyStruct(text::String)
self = new()
self.text = some_stuff(text)
return self
end
end
but for this to work the struct needs to be mutable. Then you can set up an uninitialize instance with new() and overwrite the fields.
Note that this is more equivalent to a combination of both __init__ and __new__. In Python, the new part is (99% of the time) already done for you, and you just mutate the already created empty object in __init__. In Julia, you have to do both on your own; this especially also requires returning the new value at the end of the constructor!
Having said all this, it's not often useful to write that way. More idiomatic would be just
struct MyStruct
text::String
MyStruct(text::String) = new(some_stuff(text))
end
unless you absolutely need the struct to be mutable (which has consequences with respect to memory layout and possible optimizations).
And also read up on the difference between inner and outer constructors. If you want the above to be the only valid way to construct MyStruct, this is fine. If you want "convenience constructors", e.g. with default arguments or conversions from other types, prefer outer constructors (where you don't have new but recursively call constructors until an inner constructor is reached).
Taking a quick glance at the constructors documentation and trying out the playground, I was able to come up with this:
struct MyStruct
text::String
function MyStruct(_text::String)
s = new(_text * "def")
# do other things
s
end
end
s = MyStruct("abc")
println(s.text) # abcdef

Variadic generic type alias

I'm writing a python typing stub for use with mypy. There are a lot of functions that take callback parameters of the form Callable[[*foo], Any], where *foo represents zero or more types. I would like to be able to use a generic type alias to reduce repetition.
Generic type aliases are documented here, but I don't see how it would be possible to have a list of types as a parameter.
I know that this can be done with a concrete number of arguments:
T = TypeVar('T')
Callback0 = Callable[[], Any]
Callback1 = Callable[[T], Any]
def foo(f: Callback0): ...
def bar(f: Callback1[str]): ...
What I'd like to declare instead is something like:
def foo(f: Callback[]): ...
def bar(f: Callback[str]): ...
If it matters, the code is for Python 3.3, and I'm running mypy with Python 3.7.
What about protocol?
T = TypeVar("T")
class MyAwesomeProtocol(Protocol[T]):
def __call__(self, a: T) -> Any:
pass
def foo(f: MyAwesomeProtocol):
...
def bar(f: MyAwesomeProtocol[str]):
...

How to make mypy complain about assigning an Any to an int

mypy --strict dutifully complains about the following code:
from typing import Any, Dict
def main() -> None:
my_str: str = 'hello'
my_int: int = my_str
if __name__ == "__main__":
main()
by outputting:
error: Incompatible types in assignment (expression has type "str", variable has type "int")
However the following code is accepted without any error:
from typing import Any, Dict
def main() -> None:
my_str: Any = 'hello'
my_int: int = my_str
if __name__ == "__main__":
main()
Is there an option for mypy to make it also reject the second example?
I expect it to do so, because it also rejects the following:
from typing import Any, Dict, Union
def main() -> None:
my_str: Union[int, str] = 'hello'
my_int: int = my_str
if __name__ == "__main__":
main()
with:
error: Incompatible types in assignment (expression has type "Union[int, str]", variable has type "int")
And in my understanding an Any is just the Union of all possible types.
And in my understanding an Any is just the Union of all possible types.
That's not correct. Any is an escape hatch, an annotation for variables that you want the type checker to ignore. It certainly is not a union.
From the mypy documentation on Any:
A value with the Any type is dynamically typed. Mypy doesn’t know anything about the possible runtime types of such value. Any operations are permitted on the value, and the operations are only checked at runtime. You can use Any as an “escape hatch” when you can’t use a more precise type for some reason.
(Bold emphasise mine)
It explicitly covers your case:
Any is compatible with every other type, and vice versa. You can freely assign a value of type Any to a variable with a more precise type:
a: Any = None
s: str = ''
a = 2 # OK (assign "int" to "Any")
s = a # OK (assign "Any" to "str")
Declared (and inferred) types are ignored (or erased) at runtime. They are basically treated as comments, and thus the above code does not generate a runtime error, even though s gets an int value when the program is run, while the declared type of s is actually str!
So the correct approach is to not use Any if you want the type checker to keep tracking how the value is used. Use a Union[], as you did in your third example, or re-think your data structures to allow for better type hinting. For example, rather than use a dictionary with a union value type, consider using a named tuple or dataclass with explicit fields and a specific type for each field.
For those that read about this later, the actual solution is to use the "disallow any" family of command line flags, as describes in this answer.

How to constrain the element type of an iterator?

I’m converting some older Rust code to work on 1.0.0. I need to convert a function that takes an iterator over characters, which used to be written like this:
fn f<I: Iterator<char>>(char_iter: I)
Now that Iterator doesn’t take a parameter, the constraint on I can only be I: Iterator. The element type is then I::Item. Is there a way to express the constraint that I::Item = char? (Or should I be doing this another way entirely?)
fn f<I: Iterator<Item = char>>(char_iter: I)
Associated types were recently added to the language, and many library types were updated to take advantage of them. For example, Iterator defines one associated type, named Item. You can add a constraint on the associated type by writing the name of the associated type, an equals sign, and the type you need.
Okay, I was able to figure this out from reading some RFC discussions, and the answer is that you can instantiate associated types in the trait (like signature fibration in ML):
fn f<I: Iterator<Item = char>>(char_iter: I)
Soon it should be possible to use equality constraints in where clauses, but this doesn’t work in 1.0.0-alpha:
fn f<I: Iterator>(char_iter: I) where I::Item == char
You can write I: Iterator<Item = char>. At some point in the future, a where clause like where I::Item == char may work too, but not now.

Is it possible to implement the equals operator for different types in Rust?

As seen in How can an operator be overloaded for different RHS types and return values? you can implement some operators, eg. Add on multiple types using a work around.
Is a similar thing possible for the PartialEq trait?
I've tried various things, but the closest I can get is creating a fake trait Foo, implementing PartialEq on &Foo (since it's a trait you can't implement it on Foo) and then doing:
let x:Bar = ...
let y:FooBar = ...
if &x as &Foo == &y as &Foo {
...
}
The Equiv trait looks like it should be used for this, but as far as I can tell, implementing Equiv doesn't have anything to do with the == operator.
Is there a way to do this?
The == operator is only overridable via the PartialEq trait, and thus usable with matching types. Any other form of equality/equivalence needs a custom function/method, you can use the Equiv trait, although values that are equivalent should theoretically also have the same hash (or else HashMap.find_equiv won't work as you expect).

Resources