valpackett / magicbane

A web framework that integrates Servant, EKG, fast-logger, wai-cli… | now on https://codeberg.org/valpackett/magicbane

Home Page:https://codeberg.org/valpackett/magicbane

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

{instance (Default α) ⇒ DefConfig α} breaks things

akhra opened this issue · comments

• Overlapping instances for DefConfig SystemEnv
        arising from a use of ‘gFromEnvCustom’
      Matching instances:
        instance data-default-class-0.1.2.0:Data.Default.Class.Default α =>
                 DefConfig α
          -- Defined in ‘Magicbane’
        instance DefConfig {redacted}
          -- Defined at {redacted}
    • In the expression:
        gFromEnvCustom Option {dropPrefixCount = 1, customPrefix = ""}
      In an equation for ‘fromEnv’:
          fromEnv
            = gFromEnvCustom Option {dropPrefixCount = 1, customPrefix = ""}
      In the instance declaration for ‘FromEnv {redacted}’

This happens if Magicbane is imported anywhere in the module's upstream dependency tree, even hiding everything; hooray for global instances. It's particularly disturbing that I have no idea where a Default instance could have possibly come from for the type I'm trying to parse into.

In this case I'm able to work around it by only importing Magicbane.App and Magicbane.HTTPClient upstream. However, Default is a widely-reviled antipattern and by preference I'd have it gone even if it didn't make things explode. On the other hand, killing it could cause significant downstream breakage.

Magicbane is imported anywhere in the module's upstream dependency tree

Wow, you're always doing some interesting stuff :) Magicbane was not intended to be used in libraries, only in applications.

Default is a widely-reviled antipattern

Huh? Haven't heard about that. I like Default.

I meant module dependencies, not package -- e.g. A imports B, B imports Magicbane, A has this breakage.

I did also pull some code out into a library for sharing between different microservices. But shh. ;)

As for Default: the simplest answer is that it is a class which effectively does nothing other than remove type safety. For any instance Default Foo you could instead provide a unique defaultFoo with the same amount of effort, and consumers of that value don't have to worry that they accidentally gave it the wrong type but one that still typechecks -- and this might seem like it should be a corner-case, but Data.Default provides a pile of instances for things like Maybe a and even (r -> a), and it doesn't take much searching to find horror stories about debugging the results.

For more nuanced commentary (and a few counterarguments), wander through the comments here. Several good blog links, threads by Tekmo and others.

hm, yeah, I guess, we don't really need that Default. I like being able to just type def instead of looking up defaultWhatExactly, but it's not really that important.

Also I guess I'll make Magicbane a reexport+orphan only module…