# Announcing Elm Codegen!

**URL:** <https://discourse.elm-lang.org/t/announcing-elm-codegen/8576>\
**Category:** Show and Tell\
**Created:** [August 16, 2022, 1:01pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576 "2022-08-16T13:01:59Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![mdgriffith](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mdgriffith/32/61_2.png) [@mdgriffith](https://discourse.elm-lang.org/u/mdgriffith)\
**Post date:** [August 16, 2022, 1:01pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/1 "2022-08-16T13:01:59Z")

</div>

👋 Hello!

I’m super excited to announce `elm-codegen`, an _Elm package_ and _CLI tool_ for generating Elm code!

- Here is [the package on NPM](https://www.npmjs.com/package/elm-codegen)
- And the [code docs on the Elm package website](https://package.elm-lang.org/packages/mdgriffith/elm-codegen/latest/)

My goal is to make it easy to write maintainable code generation for Elm.

Basically I wanted something that was easier to write than that string template you have lying around. 😏 And more maintainable than juggling a raw AST.

Here’s a simple example!

This code

```elm
Elm.declaration "anExample"
    (Elm.record
        [ ("name", Elm.string "a fancy string!")
        , ("fancy", Elm.bool True)
        , ("theTime", Gen.Time.millisToPosix 0)
        ]
    )

```

will generate the following:

```elm
import Time

anExample : { name : String, fancy : Bool, theTime : Time.Posix }
anExample =
    { name = "a fancy string!"
    , fancy = True
    , theTime = Time.millisToPosix 0 
    }

```

Let’s break down what this tool does for you in order to make generating code simpler.

1. _Automatic imports_ — Import declarations are calculated. If you use a value from another module, it will know and write your import declarations accordingly.
2. _Built in type inference_ — The types for your generated code are inferred. This means generated things can figure out their own type signatures!
3. _Use existing packages easily_ — For generating code that uses a specific _library_ such as [elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/1.1.8/), the `elm-codegen` CLI can create some Elm code to help you out. In the above example, we’re using generated bindings to the `elm/time` package.

## Using Existing Packages

Let me elaborate on the 3rd point for a moment because this turned out to be one of the most interesting aspects for me.

Using the `elm-codegen` CLI, you can install bindings to any package from the Elm universe.

For example — running `elm-codegen install elm/html` will create the following files —

- `Gen/Html.elm`
- `Gen/Html/Attributes.elm`

These will help us generate calls to `Html`. What does that look like? Well, we can now write something like this:

```auto
import Gen.Html
import Gen.Attributes

div : Elm.Expression
div =
    Gen.Html.div
        [ Gen.Html.Attributes.class
            "hello"
        ]
        [ Gen.Html.text
            "Hello world!"
        ]

```

Which will generate

```auto
Html.div
    [Html.Attributes.class "hello"]
    [Html.text "Hello world!"]

```

And would automatically include imports for `import Html` and `import Html.Attributes`

Crazy, right?

The generated helpers also include a number of other ways it can assist you, but for me, this basic mirroring of how you would interact with a library normally makes things very intuitive in a lot of cases.

## The Guides

There is a very succinct guide to get people started:

- [Getting started](https://github.com/mdgriffith/elm-codegen/tree/main/guide/GettingStarted.md)
- [Writing a generator](https://github.com/mdgriffith/elm-codegen/tree/main/guide/WritingAGenerator.md)
- [Using packages](https://github.com/mdgriffith/elm-codegen/tree/main/guide/UsingHelpers.md)

Also, major thanks to Leonardo Taglialegne aka `@miniBill`, you’ve been a massive help in developing this tool from the very beginning, I’m incredibly grateful 🙏

## Live, at Strange Loop!

I’m going to be giving a [talk on this library at Strange Loop](https://www.thestrangeloop.com/2022/codegen-with-types-for-humans-by-humans.html) on this and a bunch of related work that is built on top of it (that will hopefully be ready for release soon!)

## We use this at [Vendr.com](http://Vendr.com)

We have roughly 300k lines of Elm code at [Vendr.com](http://Vendr.com), a wonderful, talented Elm team, and use Elm CodeGen to power our new GraphQL library (which I will be posting about very soon.)

I also have some fun stuff in the works with regards to this and `elm-ui`!

Happy to answer any questions. Lots more to come!

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [August 17, 2022, 8:59am UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/2 "2022-08-17T08:59:25Z")

</div>

I will summarise the question and answer I had on Slack so that it is preserved here for posterity:

Q: Does the package helper work for all published Elm packages?  
A: Yes it does, and has been verified against all the Elm docs JSON.

Very nice feature, well done with that! Until now I was using my [elm-syntax-dsl](https://package.elm-lang.org/packages/the-sett/elm-syntax-dsl/latest/) but manually writing generators against the packages I was using and this could be a real time saver.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [August 17, 2022, 9:01am UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/3 "2022-08-17T09:01:28Z")

</div>

There is something else I am curious about… the type checker? I seem to recall Evan mentioning that to make it efficient in the compiler mutable state is needed, which I guess is possible in Haskell but not in Elm. Is that something you found when porting the type checker from the compiler into Elm?

---

<div class="post-metadata">

**Author:** ![mdgriffith](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mdgriffith/32/61_2.png) [@mdgriffith](https://discourse.elm-lang.org/u/mdgriffith)\
**Post date:** [August 17, 2022, 12:08pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/4 "2022-08-17T12:08:44Z")

</div>

Yeah! One of the final tests I did was `elm-codegen install` for every package and confirmed that the generated bindings compiled. If people are interested in a cache of all the docs.json files for the package website, I also created this repo: [GitHub - mdgriffith/elm-all-docs: A cache of all the docs.json files on the Elm Package website](https://github.com/mdgriffith/elm-all-docs)

Good question! Right, as I understand it, any pure language is going to run into some challenging performance issues during type unification.

So far I haven’t actually run into this in the wild though. So, maybe it just matters less for this project than for a full language?

My thinking is

1. `elm-codegen` is doing less typechecking work than a proper language. (e.g. we’re not directly resolving values from an imported module)
2. In much the same way you can `elm-codegen install {package}`, you can also `install` local Elm files and it will generate some code to help you call that local file. This is an effective way to reduce load on the type inference in `elm-codegen` because those “helper files” effectively have all their type inference work for them already baked in.

If people _do_ end up with a challenging performance situation, there are a few options to explore.

1. I imagine my existing code could be sped up via normal means.
2. [GitHub - mdgriffith/elm-optimize-level-2](https://github.com/mdgriffith/elm-optimize-level-2)
3. Add the ability to turn off type inference in the library

I imagine there are other things that could be done too.

So, if we notice performance being an issue, please file an issue on the repo! Happy to look into it further.

---

<div class="post-metadata">

**Author:** ![ni-ko-o-kin](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ni-ko-o-kin/32/2693_2.png) [@ni-ko-o-kin](https://discourse.elm-lang.org/u/ni-ko-o-kin)\
**Post date:** [August 19, 2022, 11:11am UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/5 "2022-08-19T11:11:06Z")

</div>

I don’t want to be rude, but I don’t get the examples… they are very abstract to me. Maybe you could give a more concrete/real-world example?

Maybe I’m not the kind of elm-user this is intended for. The first thing that I hoped I could solve is to generate a List of custom type values:

```auto
type Animal = Dog | Cat | Snake

```

`gen-magic...`

generates:

```auto
animals : List Animal
animals = [Dog, Cat, Snake]

```

Could this tool be used for that kind of code gen, or am I totally on the wrong path here?

---

<div class="post-metadata">

**Author:** ![mdgriffith](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mdgriffith/32/61_2.png) [@mdgriffith](https://discourse.elm-lang.org/u/mdgriffith)\
**Post date:** [August 19, 2022, 12:52pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/6 "2022-08-19T12:52:59Z")

</div>

Not rude at all! I actually love these kinds of questions. And code generation is actually kinda mind bending, even if there is a nice library to support it.

If you wanted to generate that custom type, you would write this

```elm
module Main exposing (main)

import Browser
import Elm
import Elm.ToString
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

myElmStuff =
    Elm.customType "Animal"
        [ Elm.variant "Dog"
        , Elm.variant "Cat"
        , Elm.variant "Snake"
        ]

main =
    let
        rendered =
            Elm.ToString.declaration
                myElmStuff
    in
    Html.pre []
        [ Html.text rendered.body
        ]

```

Which you can check out in this [ellie example](https://ellie-app.com/jnwNYCFL5B3a1). And [here are the docs where it talks about that](https://package.elm-lang.org/packages/mdgriffith/elm-codegen/1.0.0/Elm#customType).

The easiest way to get started with this library is to play around with stuff purely in Elm, like the Ellie example is doing. Honestly I should add a bunch of Ellies to get people started.

The only “magic” is really the `elm-codegen` CLI tool, but you can skip that part while getting familiar with the library.

Let me know if you have more questions, I’m happy to discuss. Your perspective is helpful!

---

<div class="post-metadata">

**Author:** ![IloSophiep](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ilosophiep/32/3489_2.png) [@IloSophiep](https://discourse.elm-lang.org/u/IloSophiep)\
**Post date:** [August 19, 2022, 2:01pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/7 "2022-08-19T14:01:26Z")

</div>

> [@mdgriffith](#):
>
> Let me know if you have more questions, I’m happy to discuss. Your perspective is helpful!

The way I understood the question was not “how codegen the type `Animal`?” but instead I think the question was “how do I codegen the constant `animals` with the given type `Animal`?”

Hope I don’t misunderstand stuff here…!

---

<div class="post-metadata">

**Author:** ![ni-ko-o-kin](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ni-ko-o-kin/32/2693_2.png) [@ni-ko-o-kin](https://discourse.elm-lang.org/u/ni-ko-o-kin)\
**Post date:** [August 19, 2022, 5:23pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/8 "2022-08-19T17:23:50Z")

</div>

Yes. How to generate a list of variants was my question.

Here is my [ellie](https://ellie-app.com/jnBXSt5CKs4a1) so far. It generates a list of strings, because I don’t know how to turn the Variant-Type into an Expression. See line 30 (commented).

> Not rude at all! I actually love these kinds of questions. And code generation is actually kinda mind bending, even if there is a nice library to support it.

@mdgriffith It looks lilke a very powerfull tool, once you understand how to use it, which I don’t yet 😉

---

<div class="post-metadata">

**Author:** ![mdgriffith](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mdgriffith/32/61_2.png) [@mdgriffith](https://discourse.elm-lang.org/u/mdgriffith)\
**Post date:** [August 19, 2022, 5:30pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/9 "2022-08-19T17:30:53Z")

</div>

You want to check out `Elm.value`!

I made the changes here:  
[https://ellie-app.com/jnC3DSLD8LKa1](https://ellie-app.com/jnC3DSLD8LKa1)

---

<div class="post-metadata">

**Author:** ![ni-ko-o-kin](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ni-ko-o-kin/32/2693_2.png) [@ni-ko-o-kin](https://discourse.elm-lang.org/u/ni-ko-o-kin)\
**Post date:** [August 19, 2022, 6:16pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/10 "2022-08-19T18:16:45Z")

</div>

Thank you very much!!! 🎉 🙏

---

<div class="post-metadata">

**Author:** ![mdgriffith](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mdgriffith/32/61_2.png) [@mdgriffith](https://discourse.elm-lang.org/u/mdgriffith)\
**Post date:** [August 19, 2022, 6:53pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/11 "2022-08-19T18:53:57Z")

</div>

No problem! 🎉

You’ve made me realize I should probably extend this guide: [elm-codegen/WritingAGenerator.md at main · mdgriffith/elm-codegen · GitHub](https://github.com/mdgriffith/elm-codegen/blob/main/guide/WritingAGenerator.md)

To cover some more real examples.

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [August 29, 2022, 6:54pm UTC](https://discourse.elm-lang.org/t/announcing-elm-codegen/8576/12 "2022-08-29T18:54:38Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
