Skip to content
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

Making getAddrInfo polymorphic #587

Merged
merged 12 commits into from
Sep 11, 2024
Merged

Conversation

kazu-yamamoto
Copy link
Collaborator

The recent GHCs warn partial pattern matchings and partial functions.
So, let's provide getAddrInfoNE:

Since GHC 9.8 or later warn partial functions, I begin to think to provide:

getAddrInfoNE
    :: Maybe AddrInfo
    -> Maybe HostName
    -> Maybe ServiceName
    -> IO (NonEmpty AddrInfo)

@khibino Would you review this PR?

Copy link
Contributor

@endgame endgame left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth putting a {-# DEPRECATED #-} on getAddrInfo, and laying out a migration plan of:

  • Remove getAddrInfo
  • Re-add getAddrInfo = getAddrInfoNE, deprecate getAddrInfoNE
  • Remove getAddrInfoNE?

@kazu-yamamoto
Copy link
Collaborator Author

It is a nice idea to put DEPRECATED onto getAddrInfo.
But to maintain the backward compatibility, I would not like to do the other steps.

@kazu-yamamoto
Copy link
Collaborator Author

kazu-yamamoto commented Aug 30, 2024

It would be worth making getAddrInfo polymorphic.

Roughly,

getAddrInfo
    :: (??? t)
    => Maybe AddrInfo
    -> Maybe HostName
    -> Maybe ServiceName
    -> IO (t AddrInfo)
    ```

@kazu-yamamoto
Copy link
Collaborator Author

@endgame d97f57d implements the polymorphic getAddrInfo.
I hope you like it.

@endgame
Copy link
Contributor

endgame commented Aug 30, 2024

Some thoughts, which might conflict with each other:

  • Does GHC let us deprecate instances yet?
  • Have you considered only exporting the method and not the typeclass? I don't know if that makes the haddocks too confusing but I can't see anyone else needing to create an instance. An appropriate haddock on the method would make it clear that the NonEmpty instance is preferred but the [] instance works.

-> IO (NE.NonEmpty AddrInfo)
getAddrInfoNE hints node service =
-- getAddrInfo never returns an empty list.
NE.fromList <$> getAddrInfo hints node service
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since getAddrInfoList also does a non-empty check and throws an IO error if the list is empty, you could make getAddrInfoNE the "real" function and implement getAddrInfoList by fmapping toList over the result of getAddrInfoNE?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@kazu-yamamoto
Copy link
Collaborator Author

Does GHC let us deprecate instances yet?

I cannot find a way to deprecate instance from the GHC documentation.

@kazu-yamamoto
Copy link
Collaborator Author

Have you considered only exporting the method and not the typeclass?

OK. Done.

@kazu-yamamoto kazu-yamamoto changed the title Providing getAddrInfoNE Makeing getAddrInfo polymorphic Sep 3, 2024
@khibino
Copy link
Contributor

khibino commented Sep 3, 2024

How about not allocating the head tuple when constucting the NonEmpty AddrInfo as follows?

khibino@630cc16

@kazu-yamamoto
Copy link
Collaborator Author

@khibino 80fadc1 implements your idea with the original code logic.

getAddrInfo
class GetAddrInfo t where
-----------------------------------------------------------------------------
-- | Resolve a host or service name to one or more addresses.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rendered the haddocks, and it doesn't give the reader a way to see what instances of GetAddrInfo exist. I think we should document them here.

Alternatively, we could use the IsList class? But I think that will be more confusing and should only be for -XOverloadedLists support.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that IsList is confusing.
1411634 improves the doc.

@khibino
Copy link
Contributor

khibino commented Sep 4, 2024

IsList example:
khibino@3bc61f1

Applicative and Semigroup example:
khibino@0141ba2

Which type signature would be better?

@endgame
Copy link
Contributor

endgame commented Sep 5, 2024

IsList example: khibino@3bc61f1

Applicative and Semigroup example: khibino@0141ba2

Which type signature would be better?

I think Applicative × Semigroup doesn't necessarily give you right semantics (it requires (<>) = liftA2 (<>) which is common but by no means universal.) I agree with @kazu-yamamoto that IsList looks confusing. I think the design decision reduces to: do we make the function polymorphic with a custom typeclass, or do we make two distinct named functions and deprecate the [] one? I could go either way. It's a real shame that we can't deprecate typeclass instances.

@kazu-yamamoto
Copy link
Collaborator Author

@endgame I like the current implementation.

@kazu-yamamoto
Copy link
Collaborator Author

Is this ready for merging?

Copy link
Contributor

@endgame endgame left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some final thoughts, most small. I reworded the haddock too.

Network/Socket/Info.hsc Outdated Show resolved Hide resolved
Network/Socket/Info.hsc Outdated Show resolved Hide resolved
Network/Socket/Info.hsc Outdated Show resolved Hide resolved
-- >>> addr <- NE.head <$> getAddrInfo (Just hints) (Just "127.0.0.1") (Just "http")
-- >>> addrAddress addr
-- 127.0.0.1:80
getAddrInfo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A @since line might also be useful for future readers, to know when a NonEmpty is available.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@kazu-yamamoto kazu-yamamoto changed the title Makeing getAddrInfo polymorphic Making getAddrInfo polymorphic Sep 6, 2024
Copy link
Contributor

@endgame endgame left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems good. One final nit (my fault, sorry) and a thought for future work. Thank you for this.

Network/Socket/Info.hsc Outdated Show resolved Hide resolved
| ptr_ai == nullPtr = return []
-- POSIX requires that getaddrinfo(3) returns at least one addrinfo.
-- See: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html
| ptr_ai == nullPtr = ioError $ mkIOError NoSuchThing "getaddrinfo must return at least one addrinfo" Nothing Nothing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to capture errno in the IO error, but that's out of scope for this PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error reporting of network is historically poor.
We should implement a mechanism to maintain error numbers in the future.

@kazu-yamamoto kazu-yamamoto merged commit a7b15f8 into haskell:master Sep 11, 2024
13 of 14 checks passed
@kazu-yamamoto kazu-yamamoto deleted the non-empty branch September 11, 2024 00:32
@kazu-yamamoto
Copy link
Collaborator Author

Merged.
Thank you for your review.
I will release a new version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants