One of the things I appreciate about the design of Shards is the ability for multiple owners to contribute their own shard for a purpose – I can build a redis adapter and share it, and so can you. And someone else. We can work together and avoid a landrush.
But how do I write a library that is capable of handling “whatever redis” you give me?
It’s easy for me to write this because I know the type of redis_url
– a string:
require "redis"
module Library
class Config
property redis_url : String
end
end
Library::Config.new.redis_url = "redis://localhost:6379"
It’s also easy for me to declare that I might want property redis_instance : Redis::PooledClient
if I know that you’re using a Redis library that provides that feature.
What I can’t find a solution for is as follows. I’d like for the user of my library to be able to pass in an instance of an unknown class, which obeys an interface:
module Library
class Config
property redis_instance : ???
end
end
Library::Config.new.redis_instance = Redis::Connection.new "redis://localhost:6379"
In this case, I only need the redis instances to have these methods: #hget, #hgetall, #hset, #expire, #del, #ttl, #increment, #hincrby, #flushall, #lpush, #lrem, #zcount.
- Typing
redis_instance
as a generic Class doesn’t work because the compiler doesn’t believe that the methods I need will be defined. - Inheritance doesn’t work – this would create an N-interfaces for N-projects problem
- Duck Typing would work but I don’t know how to lead the compiler, if it’s even possible.
Library flexibility isn’t the only reason I’d like to achieve this. I’d also like to share the connection pool of the host application. For other databases, this could be an important and even expensive distinction – if embedding my library in an app requires 2 connection pools, that may require someone to pay for a higher tier of a database or be faced with limited horizontal scaling because the number of connections is too high.