My main objection:
my $foo = io('some/thing');
Yes it would be better to trap such a mistake ASAP. Would this be OK?my $foo = io(-filename => 'some/thing');
You could even add some kind of policy enforcement aspect that will trap all dubious instantiations on runtime.
I am not worried about a developer calling $foo->slurp when the intention was to use $foo as a directory, for the same reason that I am not worried about it being used as a Person object. It is just a coincidence that file and directory features are in the same physical package.
BTW: The Java class java.io.File is also a file or a directory, and it implements some methods that are directory specific, like listFiles(). So it is a similar situation, despite the static typing. Of course that is a poor example, and anybody with a brain would use a util lib, e.g. the apache commons.
It is leaky abstraction, but it looks like a pretty cool one to me! The freedom from having to check return values is a justification for this by itself.