This page looks best with JavaScript enabled

snake_case in Cargo sucks

 ·  ☕ 5 min read

When you’re deciding on a naming convention for Cargo tables or fields, you have a few options1:

I don’t have a strong opinion between PascalCase and camelCase, do whichever you prefer, just try to be consistent. But snake_case kind of sucks.2

Let’s go through an example together.

The table

Here is my cargo_declare:

{{#cargo_declare:_table=Items
|attack=Integer
|ability_power=Integer
|armor=Integer
|mana_per_second=Integer
}}

And here is a screenshot of Special:CargoTables for my stored data:

You will notice that even though I wrote underscores in the field names (ability_power and mana_per_second) in my declare, Special:CargoTables is displaying spaces in the field names. This is already a bit unfortunate and confusing, but it gets worse….

The problem in format=template

If you ever use format=template on your wiki (and even if you don’t, someone else will one day), you may have something like the following:

{| class="wikitable"
{{#cargo_query:table=Items
|fields=attack, ability_power, armor, mana_per_second
|format=template
|named args=yes
|template=ItemRow
}}
|}

Then at Template:ItemRow you have the following (note the blank line at the start of the template):


| {{{attack}}} ATK
| {{{ability_power}}} AP
| {{{armor}}} AR
| {{{mana_per_second}}} M/s
|-

You will get this3:

How to debug

I wrote an entire blog post about this in 2021. I’m not sure why I didn’t also write this post then, but better late than never.

What to do instead

What you should do instead is use either PascalCase or camelCase and never encounter this issue. But if you are working on a very established wiki that has been using snake_case for a long time, here is how you can make your code work.

Cargo reformats all snake_case fields to have spaces instead of underscores in format=template. So, make this the code at Template:ItemRow (again note the blank line at the top):


| {{{attack}}} ATK
| {{{ability power}}} AP
| {{{armor}}} AR
| {{{mana per second}}} M/s
|-

Then it will work4:

Also the API does the same thing

If we make this query:

1
2
3
4
5
6
7
8
{
	"action": "cargoquery",
	"format": "json",
	"limit": "1",
	"tables": "Items",
	"fields": "attack, ability_power, armor, mana_per_second",
	"formatversion": "2"
}

Then here is our response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "cargoquery": [
        {
            "title": {
                "attack": "5",
                "ability power": "5",
                "armor": "5",
                "mana per second": "5"
            }
        }
    ]
}

Once again, spaces instead of underscores. This means that even if you aren’t using format=template, you may still get API consumers who are confused about what fields they should be receiving!

Couldn’t we just, like, patch Cargo?

I would love to but this would be a major breaking change. Think about the following issues:

  • If we provide BOTH the version with the underscores and also the version with the spaces, then we have these problems:
    • In Lua, using pairs over frame.args will give you confusing duplicate results. This is probably unlikely to be an issue in production but will be very confusing when debugging (and could sometimes be an issue in production).
    • Any time you are doing this, consider:
      1. Someone uses escape-concat formatting in a Cargo query
      2. The escape-concat formatting calls a template that includes an iterator variable
      3. We have to parse this twice, once with the underscore in the field name and once without
      4. Uhoh (and no we couldn’t “just parse it only once”)
  • If we provide ONLY the version with the underscores then everything stops working

So this clearly requires a breaking change. One possibility is the following changes in cargo_query:

  1. |named args= gets deprecated and we add a tracking category if thats defined
  2. |args= is added with 3 values: numeric, exact, and reformat:
    • numeric is the behavior you get if you set named args=no currently
    • exact gives you underscores when fields are snake_case, i.e. the behavior we want
    • reformat gives you the current named args=yes behavior with spaces replacing underscores
  3. At some point in the future (think 5 years from now) hopefully drop support for named args, and default |args= to exact (probably behind a feature flag)

I’d love to hear feedback on this to see if it’s worth pursuing!


  1. For completeness of listing cases, there’s also kebab-case, which is used in HTML attributes and CSS properties. It is not valid in Cargo. ↩︎

  2. I realize my title for this post is a bit contentious. But I want both people who already use snake_case in their tables (and are potentially sometimes confused by why things aren’t working) and also people who don’t yet use Cargo at all to find the title resonant. A title like “Don’t use snake_case in Cargo” wouldn’t reach the first audience as effectively, so I went for this. ↩︎

  3. Please note, I do not recommend EVER using argument names without the pipe, so for example you should always be writing {{{attack|}}} rather than {{{attack}}} (possibly with some if-statement validation surrounding it). But I wanted the issue to really really really stand out in the screenshot, so I did something that I consider illegal. Sorry. ↩︎

  4. But you should still be writing {{{attack|}}} rather than {{{attack}}}!!!!! I just made the minimal possible diff here to make it clear what’s going on. ↩︎

Share on

river
WRITTEN BY
River
River is a developer most at home in MediaWiki and known for building Leaguepedia. She likes cats.

What's on this Page