Skip to content

Loading…

[RFC] address hash key and value in one line #127

Closed
liuggio opened this Issue · 12 comments

8 participants

@liuggio

Hi, in order to be simple as possible this RFC will add a little of ambiguousness

I think this valid toml is too difficult to read

[database.ports]
primitive = "Array"
required = true

    [database.ports.range]    
    min = 0

    [database.ports.content]
    primitive = "Integer"

    [database.ports.content.range]
    min = 1024
    max = 49151

so I propose this:

[database.ports]
primitive = "Array"
required = true
range.min = 0
content.primitive = "Integer"
content.range.min = 1024
content.range.max = 49151

The file is not a valid toml file because:

  • I defined a key and its value in a single line.
  • I handled a keygroup as a normal key and I omitted the full path.

:+1: for me of course.

@liuggio liuggio referenced this issue
Open

Added Schema validator specification #116

0 of 3 tasks complete
@tnm

I see the motivation, but are people going to nest things like [database.ports.content.range] that deeply? I'd think the nesting would be more shallow. I'm not sure we want to support multiple ways of doing this, more generally.

@rcarver

I agree to prefer minimal nesting. What's the benefit over this?

[database.ports]
primitive = "Array"
required = true
range_min = 0
content_primitive = "Integer"
content_range_min = 1024
content_range_max = 49151
@liuggio

you changed behaviour thay are objects , I think the same benefit of doing this

database_ports_primitive = "Array"

@tnm please have a look to the PR attached, the Hash in one line could reduce a lot lines.

@mojombo

I'm torn on this. One one hand, it makes sense, and solves the problems you bring up. On the other hand, it adds complexity, and gives you multiple ways to do things, and increases the chances of shooting yourself in the foot. Will keep thinking. I'm open to more arguments either way.

@parkr

:-1: to shooting oneself in the foot. The more ways there are to do something, the greater the likelihood of confusion and the more difficult it is for newcomers to understand what they read.

@hilbix

I personally like to have configuration information which is nested 20 levels or deeper. Because my projects need them. Also there is trainloads of information to serialize and deserialize.

So I would find above syntax handy, with another addition:

Continuations could be added using a dot (.) in front or back of keys, like this (dot at the end defines a root, dot in front uses this root as a prefix. Easy to parse, not difficult to implement, just one global variable):

[node1.]
# We are now rooted at node1
value = 1  # defines node1.value=1
sub1.value = 2 # defines node1.sub1.value=2
[.sub.sub]
# enters node1.sub.sub
value = 3 # gives node1.sub.sub.value = 3
key = whatever # node1.sub.sub.key = whatever
[.another.sub]
# we are now in node1.another.sub
value = 4 # node1.another.sub.value = 4
[.keep.]
# We are at node1.keep, rooted
value = 5 # node1.keep.value = 5
[.subnode1]
# node1.keep.sub
value = 6
[.subnode2]
# node1.keep.sub2
value = 7

# let's make a copy of node1
[node2.]
value = 1
sub1.value = 2
[.sub.sub]
value = 3
key = whatever
[.another.sub]
value = 4
[.keep.]
value = 5
[.subnode1]
value = 6
[.subnode2]
value = 8 # This is different to node1

You can extend this with .. and ... to define a second or third "root". But the use of a higher level root should invalidate a lover level one, just to make it more easy to humans to find the right root again (and some better error detection on the parser).

Using .. to go up the tree like in directories is bad, because I found out, that configuration using this syntax starts to become very confusing to maintain, because humans are not good as a recursive parser. But the way it is expressed above it is very easy to track:

If you see something starting with a dot look upwards until you find something ending on a dot. With two dots do the same looking for two, and so on. There it is rooted. This is quick and convenient at once, because irrelevant information can be hidden.

This . convention conserves an enormous typing effort (one of my non-TOML configuration using this recipe is over 300 KB long) while as well making parts easily reusable for copy and paste without search and replace afterwards (for example if you have 99 nodes which are very similar). Also it improves "diff" if you need to, for example, replace "node1" by "node0". YKWIM.

Sorry, no patch to TOML from me, because I did not use it yet (stumbled on TOML today).

BTW, on keys using the dot notation, you can leave away the brackets, because the dot-syntax is not ambiguous (it always starts on a line, probably indented):

node1..  # alias of [node1..] defines level 2 root node1
..node2 # alias of [..node2]
..node3. # alias of [..node3.] defines 1nd root node1.node3
.lev2 # alias of [.lev2]
.subnode. # alias of [.subnode.]
..node4 # alias of [..node4]
.lev3 # syntax error, 1st root invalid after 2nd root is reused
. # alias of [.] is a syntax error
node3 # syntax error, no dots

EDIT: Levels reversed, such that you can wrap (copy and paste) inner roots into outer roots (using more dots).

@ricardobeat

@hilbix your own example is more readable with TOML as-is:

[node1]
value = 1

    [node1.sub1]
    value = 2

    [node1.sub]
    value = 3
    key = whatever

    [node1.another.sub]
    value = 4

    [node1.keep]
    value = 5

        [node1.keep.subnode1]
        value = 6

        [node1.keep.subnode2]
        value = 7
@BurntSushi
toml-lang member

@ricardobeat +1. @hilbix's suggestion feels like it very much goes against the "minimal" aspect of TOML.

@hilbix

@ricardobeat

I see it differently. You are right if your configuration is just a half page of information. But as soon as configuration becomes a bit more complicated, you will quickly see how important reuse of sections can be and how important relative paths (in keys) are.

To stress it: YAML is far superior to TOML as long as such or similar feature is missing. YAML supports relative hierarchies and copy of them without excess search and replace. TOML does not.

In real life you need a configuration language which is powerful enough to express all your needs. It must not leave you alone in somewhat more complex situations. And it must support quick changes.

For example my OID is 1.3.6.1.4.1.8505.1.568 which would translate to [iso.org.dod.internet.private.enterprise.skytec.misc.tino] in TOML. OIDs are unique by definition, so they make up ideal keys.

If you prepare a configuration with, say, some thousands of very similar assets below this OID, it is crucial that you can reuse sections and just adapt them to the changed part. With TOML today you need search and replace in that case. Clumsy compared to YAML, where you do not need to replace anything, just copy and adopt, and you are done.

And afterwards, you need to move from your development OID to some newly allocated one. With TOML toray, this involves search and replace of thousands of places, probably error prone if you are in a hurry, as always. In YAML the intro and perhaps some indentation needs changes, which is far superior (think about diff -b).

In that use case TOML cannot replace YAML. But even with short configurations, TOML has no real benefit compared to YAML. So there really is no need to replace YAML with TOML.

But with relative keys TOML suddenly becomes superior to YAML, allowing a much broader audience. Isn't that worthwhile?

A good configuration language like TOML or YAML need to fulfill following goals:

  • Easy to use in all situations.
  • Easy to maintain.
  • Human readable.

YAML fulfills the first two fully, it only is a bit difficult to be read by humans if configuration becomes bigger.

OTOH TOML only fulfills the first and the last goal, if used in an OID scenario as noted you will see that it becomes very difficult to maintain. But with this slight change (I think it can be implemented in less than 20 lines of code) would fulfill all 3 goals fully.

So the real challenge is not "purity", but to keep it human readable even if it becomes powerful.

PS: This is my last post to this issue.

@BurntSushi
toml-lang member

In real life you need a configuration language which is powerful enough to express all your needs. It must not leave you alone in somewhat more complex situations.

This is in direct opposition to the stated goals of TOML:

TOML aims to be a minimal configuration file format that's easy to read due to obvious semantics. TOML is designed to map unambiguously to a hash table. TOML should be easy to parse into data structures in a wide variety of languages.

It's hard to say exactly what "minimal" means, but I can tell you what it doesn't mean: powerful enough to express all your needs.

If you prepare a configuration with, say, some thousands of very similar assets below this OID, it is crucial that you can reuse sections and just adapt them to the changed part.

I suggest you consider the possibility that TOML is not the right tool for this job.

@BurntSushi
toml-lang member

I would very much like to close this since I see it as adding more complexity for not too much benefit. It would also be a pretty big change in how people write TOML. @mojombo, you showed some interest earlier. What do you think now?

@mojombo

@BurntSushi Agreed. Let's keep tables and keys separate.

@BurntSushi BurntSushi closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.