This results in an error that app needs a type, however, I think it would be convenient if the user didn't have to specify a type unless they were using a transport. Ideally, the user would call App::new() to create an app without a transport and App::with_transport() to create an app with a transport. Is this possible or is there a better way?
To give you an example for why you need to provide a type parameter, what would happen if the layout of a std::sync::mpsc::Sender<T> changed depending on the T?
Imagine if it stored a couple elements in-line to allow bulk sending. If that were the case a Sender<u8> might be 8 bytes long while a Sender<usize> could be 16 (the numbers aren't important here). If that were the case then Transport<T>'s size would change, causing App<T>'s size to also change.
Now the compiler runs into a problem... If it doesn't know what T is being used in App<T> then how much space should it set aside for the app variable?
Sure there might be some concrete cases where changing the type parameter won't result in layout changes (e.g. Box<T> is always the size of a pointer, regardless of the T), but in general it's not possible to know a type's layout until you substitute in all the type parameters.
There are other examples (e.g. backwards compatibility and auto traits like Send or Sized), but the layout ones were the first to come to mind.
This basically showcases what the comments above have suggested, so that:
fn main ()
{
let app = App::new("myapp".into());
}
Just Works™, with optimal size, while
fn main ()
{
let app = App::with_transport("myapp".into(), …);
}
also works
Note that if you have been using an Option for this statically-known presence or absence of transport, then I recommend you remove the Option altogether: