Distinguish Interfaces of the Arguments
Objective: Define a fucntion that:
- For arguments that implements
get_colormethod, 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