New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HTTP::FixedLengthContent not documented #9444
Comments
Mmh, In general either should be transparent and treated like a plain |
My use-case is detailed further in #9445 where I wish to get the progress of a large downloaded file |
I overlooked that this was coming from IO::Sized, so will close |
There's however a problematic aspect here: Stdlib exposes undocumented types in its API. When a returned value is of type Even if the implementation is only an internal detail, I think everything that is exposed through the public API should be documented. |
You mean that the runtime is returning a type that the user can see, but it's not documented, so it should be documented? That's not the right thing to do. The right thing to do is for the user to see that this type is not documented and so they shouldn't fiddle with it. |
@asterite I've gotten this type when using HTTP::Server and handling request-response, this should be documented as you actually do interact with it. |
So we got this fancy return type annotations y'all like so much. What happens if we add one to |
If you introspect code in Java, C#, etc., you can get named of private types. That doesn't mean they should be documented... this has been like that for years already. It's just nonsense to start documenting internal types. |
But when such a type is returned, it's for the purpose of using that type, right? How's the user supposed to know how to do that when it's not documented? It's just useless without any information. In Java, this is not so much a problem because type restrictions work differently and apply stronger. The stdlib typically uses public interfaces as fronts for internal types. So while the actual type might be some internal private class, to the user it behaves as the interface type. You can't call methods on the implementation type if they're not in the inteface. The internal type is only visible when you ask for it (for example calling That's all different in Crystal. Even if you use an interface as type restriction, the compiler still resolves that to the actual types covered by that (more or less) and to the user there's no difference from using the private type. Example: interface Foo { }
private class FooImpl implements Foo {
public void implementationDetail() { }
}
Foo getAFoo() {
return new FooImpl();
}
// This works:
Foo foo = getAFoo();
// This doesnt:
FooImpl foo = getAFoo();
// This doesn't work in either case:
foo.implementationDetail(); module Foo; end
class FooImpl
include Foo
def implementation_detail
end
end
def get_a_foo : Foo
FooImpl.new
end
# Both work:
foo : Foo = get_a_foo()
foo : FooImpl = get_a_foo()
# This also works:
foo.implementation_detail() |
What method are we talking about? If it's body_io, that's an IO. |
The type restriction of |
@straight-shoota Wrong, because when you execute the code with a Java debugger you will see the actual type. |
What people are proposing here basically means "let's get rid of private types and hiding implementation details". |
Yes, in Java you can still reflect on the value and determine the actual type. I've mentioned this explicitly in my previous comment. In Crystal however, even though So other than Java, users of such a method in Crystal easily get to interact with the supposedly private, internal type, thus leaking that implementation detail to the public. |
You know what other language works that way? Ruby! Yes, Ruby leaks implementation everywhere. Ruby was and is still our inspiration. I never found this to be a problem in Ruby. If there's a type I don't know and it's not documented, I don't fiddle with it. Or yes, I go to the source code and check how it works, but I never try to use their methods because I know they are implementation details. |
This is probably true also in Python and many other dynamic languages. Yes, at runtime, or even at compile-time in Crystal you will learn the types with If we really want to change it we need to automatically cast return values to their return type annotations. Maybe that's a solution, I don't know... I really don't think this is an issue. |
For languages like Ruby and Python that's not so much of an issue. In dynamically typed languages developers tend to care less about types. It's pretty rare that you do any type checks in those languages. And it's all happening at runtime, depending on the actual values, not type grammar. I honestly don't know what a good solution would be. I just notice that the current situation is not ideal because private details are leaking into the public. Because of the way Crystal's type grammar works, that's has a stronger effect than in Java, Ruby or Python. |
Yeah... maybe we can try casting return values to the return type annotations. But that menas that if a method returns Also sorry if any of what I said above (or in other issues) sounded a bit harsh. My kid has troubles falling asleep and so am I. I guess it affects my mood whether I want it or not. |
Maybe a notion of a type being different for semantic and codegen, with the constraint that the codegen type must be a subset of the semantic type, could be useful, in general? Here that would allow us to have the semantic type be that of the return type restriction, while preserving the actual concrete type for codegen. But yeah, that's a bigger internal change. |
This has come up again in chat: https://discord.com/channels/591460182777790474/591597160492171264/913141422218149929 Undocumented internal types that leak through the public API are usually (or hopefully always) implementations of specific interfaces. The interfaces themselves are documented and the rationale is that the implementation does not need any documentation because the type itself is just a negligible internal detail and its API is completely generic regarding the interface. I think one thing we could improve is to change So maybe instead of
we could have something like
|
I'm experiencing this exact scenario. I'm trying to use |
For HTTP::Client streaming, body_io is an HTTP::FixedLengthContent and intended to be interacted with but this is no-doc'd.
From the docs
In my use-case, I needed
response.body_io.as(HTTP::FixedLengthContent).read_remaining
The text was updated successfully, but these errors were encountered: