1. 3
    1. 3

      We’d prefer the edge cases to be isolated to the calls of get_feed and not pollute the function with their single use special cases.

      This is not obvious to me.

      Looking at the example code

      get_feed(
       'https://bad-encoding.foo.com',
       fetch__encoding='latin-1')
      

      How does the caller know that fetch__encoding is an option?

      1. 2

        isn’t this a form of dependency injection? Also, I’d love to see how is that decorator implemented

        1. 2

          Yeah, I think that’s a better way to describe this - I don’t really understand what is “transparent” about this, as it requires some custom machinery to implement plus cognitive overhead to use.

          The decorator is defined here: https://github.com/iommirocks/iommi/blob/master/iommi/declarative/dispatch.py

          The parsing of the <name1>__<name2>-style arguments is done in a custom Namespace class defined here: https://github.com/iommirocks/iommi/blob/master/iommi/declarative/namespace.py

          Their project has a section on using underscores to traverse namespaces. I can’t say that I’m personally a fan of this, but can see where they’re coming from.

          1. 1

            I think the idea is that it’s transparent because the get_feed api somehow passes these lambdas through to customize behavior, rather than having the method itself apply the customizations.

        2. 2

          I’m not entirely sold by the example, since there’s only two places to be tweaked, and they could be a pass-through fetch_options dictionary and split-into-two-methods-in-the-first-place respectively.

          1. 1

            how would something like this look like when writing go?

            1. 2

              From what I understand it’s “just” dependency injection with first class functions at the end of the day (not to discredit it, it’s a powerful idea — as Greenspun would call: half of Common Lisp). So you could create a function which accepts other functions and substitute those functions when appropriate.

              type fetchFn func(net.URL) (http.Response, error)
              type decodeFn func(io.Reader) ([]byte, error)
              func getFeed(url net.URL, fetch fetchFn, decode decodeFn) (*ParsedFeed, error) {
              	response, err := fetch(url)
              	if err != nil {
              		return nil, fmt.Errorf("fetch url: %w", err)
              	}
              	data, err := decode(response.Body)
              	if err != nil {
              		return nil, fmt.Errorf("decode body: %w", err)
              	}
              	return feedparser.Parse(data)
              }
              

              But I’d say that’s probably not the most Go-like way of doing it. You eventually need to add function constructors (functions that return other functions) and it’s starts to become harder to read/understand. The language doesn’t really want you to write that kind of code. Interfaces or the functional options pattern would look more at home with Go.

            2. 1

              Am I alone in thinking they reinvented Ruby methods in Python

            🇬🇧 The UK geoblock is lifted, hopefully permanently.