Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support enumerations #14

Open
jrmiddle opened this issue Sep 22, 2017 · 1 comment
Open

Support enumerations #14

jrmiddle opened this issue Sep 22, 2017 · 1 comment

Comments

@jrmiddle
Copy link
Contributor

There are a number of cases where Sango clients would benefit from richer typing of output, especially when it comes to finite groups of elements that act as identifiers. At the moment, when Sango outputs native types, it always uses structs grouping constants of trivial type for these. For example, if I had three valid identifiers that act as keys in a configuration dictionary, I may see:

public struct Constants {

    public struct MyKeys {
        static let Key1 = "key1"
        static let Key2 = "key2"
        static let Key3 = "key3"
    }

    public struct MyAttributeIds {
        static let id1 = 1000
        static let id2 = 1002
        static let id3 = 1003
    }

}

There are a couple of disadvantages here:

  1. The developer is forced to perform runtime validity checks on values from these structs, e.g., when passing them to a method.

  2. No functionality can be added, via subclassing (java) or retroactive modeling (swift). Not all languages support this, so it's not a disadvantage for everyone, but it eliminates taking advantage of very useful features of languages that do.

If Sango were able to output enumerations for these kinds of constants, some advantages could immediately be had:

Validity checks could be performed at compile-time

Using enumerations, runtime assertions could be delegated to the compiler. For example, using the current output:

public struct Constants {

    public struct MyAttributeIds {
        static let id1 = 1000
        static let id2 = 1002
        static let id3 = 1003
    }

}

var attrs: [Int: Any] = [:]

attrs[666] = "something really important" // No error, but semantically incorrect

func set(value: Any, for attributeId: Int) {
    assert([
        Constants.MyAttributeIds.id1,
        Constants.MyAttributeIds.id2,
        Constants.MyAttributeIds.id3,
    ].contains(attributeId), "Invalid attribute id")

    attrs[attributeId] = value
 }

set("something really important", for: 666) // Caught by assertion at runtime

Instead, if Sango supported enumerations, the following would be possible:

public struct Constants {

    public enum MyAttribute {
        case id1 = 1000
        case id2 = 1002
        case id3 = 1003
    }

}

var attrs: [Constants.MyAttribute: Any] = [:]
attrs[666] = "foo" // impossible, compile-time error, pointed out in source editor.

func set(value: Any, for attribute: Constants.MyAttribute) {
    // No runtime checks required
    attrs[attributeId] = value
 }

let maybeMyAttr = Constants.MyAttribute(1000) // myAttr is .some(.id1)
let maybeMyAttr2 = Constants.MyAttribute(6666) // myAttr is .none

Retroactive modeling can be performed

Functionality can be added to enumeration cases. This can be done with strings and ints too, but those are available globally. Adding to enumeration cases limits their scope. For example:

public struct Constants {

    public enum MyAttribute {
        case id1 = 1000
        case id2 = 1002
        case id3 = 1003
    }

}

extension Constants.MyAttribute: CustomDebugStringConvertible {

    switch self {
        var name: String
        switch self {
            case .id1: name = "Attribute 1"
            case .id2: name = "Attribute 2"
            case .id3: name = "Attribute 3"
        }
        return "\(name) (\(rawValue))"
    }

}

In sum, this makes Sango output play better with developers' IDEs, and allows them to take better advantage of their compiler's facilities in particular, helping to streamline development and reduce the changes of human error.

@heyigor
Copy link
Collaborator

heyigor commented Sep 22, 2017

So enums are currently supported without specifically setting values:

Example JSON:

{
	"schemaVersion": 1,
	"java": {
		"package": "io.afero.example",
		"base": "Constants"
	},
	"swift": {
		"base": "Constants"
	},
	"javascript": {
		"base": "Constants"
	},
	"enums": {
		"MY_ATTRIBUTE": [
			"ID1",
			"ID2",
			"ID3"
		]
	}
}

Produces swift output:

/* Generated with Sango, by Afero.io */

import UIKit
public struct Constants {
	public enum MyAttribute {
		case Id1
		case Id2
		case Id3
	}
}

and java output

/* Generated with Sango, by Afero.io */

package io.afero.example;
public final class Constants {
	public enum MyAttribute {
		ID1, ID2, ID3
	}
}

So mostly there. Sango would have to support a new enum syntax in the JSON:

{
    "enums": {
        "MY_ATTRIBUTE": {
            "ID1": 1000,
            "ID2": 1002,
            "ID3": 1003
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants