Distinguish Interfaces of the Arguments
Objective: Define a fucntion that:
- For arguments that implements
get_color
method, calls this method and prints the result. - For remaining arguments prints
transparent
.
Test it where type of the argument is known in advance time and when it determined only in runtime.
Python
Abstract class can be used to define interface:
from abc import ABC, abstractmethod
from typing import Any
class Colorful(ABC):
@abstractmethod
def get_color(self):
pass
class Apple(Colorful):
def get_color(self):
return "green"
class Sky(Colorful):
def get_color(self):
return "blue"
def get_color(x: Any):
if isinstance(x, Colorful):
return x.get_color()
else:
return "transparent"
# types known in advance
print(f"{get_color(Apple())=}")
print(f"{get_color(Sky())=}")
print(f"{get_color(123)=}")
print(f"{get_color('example')=}")
# types determined in runtime
items = [Apple(), Sky(), 123, "example"]
for item in items:
color = get_color(item)
print(f"{item} is {color}")
Alternatively, existence of the methods can be checked in runtime without defining interfaces:
from typing import Any
class Apple:
def get_color(self):
return "green"
class Sky:
def get_color(self):
return "blue"
def get_color(x: Any):
if hasattr(x, 'get_color'):
return x.get_color()
return "transparent"
Yet another way of implementing get_color
:
def get_color(x: Any):
try:
get_color_ = x.get_color
except AttributeError:
return "transparent"
else:
return get_color_()
Rust
#![feature(auto_traits)] #![feature(negative_impls)] auto trait Transparent { } trait Colorful { fn get_color(&self) -> &'static str; } struct Apple; impl !Transparent for Apple {} impl Colorful for Apple { fn get_color(&self) -> &'static str { "green" } } struct Sky; impl !Transparent for Sky {} impl Colorful for Sky { fn get_color(&self) -> &'static str { "blue" } } impl<T> Colorful for T where T: Transparent { fn get_color(&self) -> &'static str { "transparent" } } fn get_color(x: impl Colorful) -> &'static str { x.get_color() } fn main() { // types known in compile time dbg!( get_color(Apple{}) ); dbg!( get_color(Sky{}) ); dbg!( get_color(123) ); dbg!( get_color("example") ); // types determined in runtime let items: Vec<&dyn Colorful> = vec![&Apple{}, &Sky{}, &123, &"example"]; for item in items { // Below we print only color of the item. Printing the items themself // needs `fmt` to be implemented and is out of the scope of this example. println!("item is {}", item.get_color() ); } }
Crystal
Abstract struct can be used to define interface:
abstract struct Colorful
abstract def get_color
end
struct Apple < Colorful
def get_color
"green"
end
end
struct Sky < Colorful
def get_color
"blue"
end
end
def get_color(x : Colorful)
return x.get_color
end
def get_color(x)
return "transparent"
end
# types known in compile time
p! get_color Apple.new
p! get_color Sky.new
p! get_color 123
p! get_color "example"
# types determined in runtime
items = [Apple.new, Sky.new, 123, "example"]
items.each do |item|
color = get_color(item)
puts "#{item} is #{color}"
end
Alternatively, existence of the methods can be checked in runtime without defining interfaces:
struct Apple
def get_color
"green"
end
end
struct Sky
def get_color
"blue"
end
end
def get_color(x)
if x.responds_to?(:get_color)
return x.get_color
end
return "transparent"
end