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

Scala support #843

Closed
wants to merge 6 commits into from
Closed

Scala support #843

wants to merge 6 commits into from

Conversation

@JannikArndt
Copy link

@JannikArndt JannikArndt commented May 4, 2018

I added scala as an output format.

JannikArndt added 5 commits May 4, 2018
@schani
Copy link
Member

@schani schani commented May 4, 2018

@JannikArndt That's amazing! Thank you.

Do you have plans to support union types eventually?

@schani
Copy link
Member

@schani schani commented May 4, 2018

There are a few compile errors:

src/language/Scala.ts(132,26): error TS6138: Property '_packageName' is declared but its value is never read.
src/language/Scala.ts(133,26): error TS6138: Property '_justTypes' is declared but its value is never read.

Also, would you mind adding Scala to the test suite? See languages.ts in test, and the very bottom of fixtures.ts. Basically you'll have to write a little driver program (in test/fixtures/scala) that deserializes JSON and then serializes it back again, and you'll have to tell the test suite how to build and run it. The Dockerfile will also have to install Scala, I guess. Or maybe Maven does that automatically?

@JannikArndt
Copy link
Author

@JannikArndt JannikArndt commented May 4, 2018

Union Types
There is no obvious and universal way to represent union types in Scala (that's the beauty of the language 😉). A colleague of mine suggested nested Either (okay for two types, ugly for more) or shapeless' hlist, which would add another dependency.
So to answer your question, if I plan to support union types eventually: If I find an adequate solution, I will definitely add it, but I'd rather not support them then add a somewhat broken support. And I am still tinkering with possible solutions.

Tests
Yeah, I did see that one coming when I looked at #838 😉 It's on my list.

Compile warnings
Fixed that 👍

@schani
Copy link
Member

@schani schani commented May 4, 2018

I thought cases classes is how you represent unions in Scala? Isn't that the equivalent to discriminated unions in ML-like languages?

We'll wait for the test suite before merging.

@schani
Copy link
Member

@schani schani commented May 4, 2018

Btw, if you need any help, it's probably quicker if you join us on Slack.

@schani
Copy link
Member

@schani schani commented May 16, 2018

@JannikArndt What's the status on this? Can we help?

@JannikArndt
Copy link
Author

@JannikArndt JannikArndt commented May 16, 2018

Hey there, sorry, I didn't have the time to write the tests, yet :(

@schani schani mentioned this pull request Jun 11, 2018
@hderms
Copy link

@hderms hderms commented Jun 11, 2018

@JannikArndt is there anything wrong with just having a sealed trait of one argument case classes to represent union types? I suppose it would play weird with singleton types like None or something so I suppose that partially answers the question.

Dotty won't become Scala 3 until 2020 as far as I've heard, so I feel like there are precious limited options in the short term.

@hderms
Copy link

@hderms hderms commented Jun 13, 2018

@JannikArndt any opposition to handling this like https://scalapb.github.io/generated-code.html

specifically the section on oneOf?

@JannikArndt
Copy link
Author

@JannikArndt JannikArndt commented Jun 17, 2018

@hderms Sounds good, I personally like the ScalaPB style. I still didn't find the time to implement anything further, though :(

@schani
Copy link
Member

@schani schani commented Jul 5, 2018

@JannikArndt @hderms I'd really like to get this closed. I'm happy to take over the work if you can give a short summary of what still needs to be done, from your point of view. If you could write a test driver (see test/fixtures/* for other language's drivers) I'd be much obliged, but I can figure it out myself if you don't have the time at all.

@hderms
Copy link

@hderms hderms commented Jul 5, 2018

@schani I'm not sure what needs to be done still but I felt like imitating the way ScalaPB does union types would be a reasonable way to do oneOf

@schani
Copy link
Member

@schani schani commented Aug 11, 2018

Doesn't look like this is moving forward, so I'm closing it for now. Please revive when/if there is new work.

@schani schani closed this Aug 11, 2018
@hderms
Copy link

@hderms hderms commented Dec 20, 2018

@schani I'm working on this now. Can you point me in the direction of a json schema or whatever that we would be expected to produce unions from? I tried test/inputs/schema/direct-union.1.json and test/inputs/schema/union.json and neither seem to produce unions in either Kotlin or Rust. Maybe those languages don't implement unions properly or am i incorrect in thinking these files should produce union'd types?

@schani
Copy link
Member

@schani schani commented Dec 20, 2018

@hderms Kotlin does not produce unions, but Rust does. It doesn't look like much in Rust, but that's because Rust's serialization framework does all the hard work. To see how to do it the hard way, look at C#, Swift, or Go.

@hderms
Copy link

@hderms hderms commented Dec 20, 2018

@schani maybe I'm misinterpreting it but I don't get how this output is a union?

npm start -- "--lang csharp test/inputs/schema/union.schema"

> quicktype@15.0.0 start /Users/dermothaughey/projects/quicktype
> script/watch "--lang csharp test/inputs/schema/union.schema"

> Watching src/
// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using QuickType;
//
//    var union = Union.FromJson(jsonString);
namespace QuickType
{
    using System;
    using System.Collections.Generic;

    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public partial class Union
    {
        [JsonProperty("$schema")]
        public Uri Schema { get; set; }

        [JsonProperty("type")]
        public string Type { get; set; }

        [JsonProperty("items")]
        public Items Items { get; set; }
    }

    public partial class Items
    {
        [JsonProperty("oneOf")]
        public OneOf[] OneOf { get; set; }
    }

    public partial class OneOf
    {
        [JsonProperty("type")]
        public string Type { get; set; }

        [JsonProperty("properties")]
        public Properties Properties { get; set; }

        [JsonProperty("required")]
        public string[] OneOfRequired { get; set; }
    }

    public partial class Properties
    {
        [JsonProperty("one", NullValueHandling = NullValueHandling.Ignore)]
        public One One { get; set; }

        [JsonProperty("two")]
        public One Two { get; set; }

        [JsonProperty("three", NullValueHandling = NullValueHandling.Ignore)]
        public One Three { get; set; }
    }

    public partial class One
    {
        [JsonProperty("type")]
        public string Type { get; set; }
    }

    public partial class Union
    {
        public static Union FromJson(string json) => JsonConvert.DeserializeObject<Union>(json, QuickType.Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this Union self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }
}

or this:

package main

import "encoding/json"

func UnmarshalUnion(data []byte) (Union, error) {
	var r Union
	err := json.Unmarshal(data, &r)
	return r, err
}

func (r *Union) Marshal() ([]byte, error) {
	return json.Marshal(r)
}

type Union struct {
	Schema string `json:"$schema"`
	Type   string `json:"type"`
	Items  Items  `json:"items"`
}

type Items struct {
	OneOf []OneOf `json:"oneOf"`
}

type OneOf struct {
	Type       string     `json:"type"`
	Properties Properties `json:"properties"`
	Required   []string   `json:"required"`
}

type Properties struct {
	One   *One `json:"one,omitempty"`
	Two   One  `json:"two"`
	Three *One `json:"three,omitempty"`
}

type One struct {
	Type string `json:"type"`
}

is union.schema expected to output an actual union type?

@schani
Copy link
Member

@schani schani commented Dec 20, 2018

Sorry, you'll have to pass --src-lang schema

@hderms
Copy link

@hderms hderms commented Dec 20, 2018

@schani my bad. That's what I get for trying to work on a project I barely understand :)

@schani
Copy link
Member

@schani schani commented Dec 20, 2018

We're also somewhat lacking in the documentation department ;-)

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

Successfully merging this pull request may close these issues.

None yet

3 participants
You can’t perform that action at this time.