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

Allow type casting to like-Object definitions #24

Open
manikmagar opened this issue Feb 13, 2021 · 3 comments
Open

Allow type casting to like-Object definitions #24

manikmagar opened this issue Feb 13, 2021 · 3 comments

Comments

@manikmagar
Copy link

Consider an Object received in an API looks like Following and can be represented as an instance of Employee type -

{
  "firstName": "Manik",
  "lastName": "Magar",
  "spokenLanguages": [
    "English",
    "Marathi",
    "Hindi"
  ],
  "departmentId": 1
}

In inheritance world, it is possible to have a structure like Employee extends Person.

Consider following dataweave script -

%dw 2.0
output application/json

type Employee = {
    firstName: String,
    lastName: String,
    spokenLanguages: Array<String>,
    departmentId: Number
}

type Person = {| firstName: String, lastName: String |}

fun getName(p:Person): String = "$(p.firstName) $(p.lastName)"

var empExample: Employee = {
  "firstName": "Manik",
  "lastName": "Magar",
  "spokenLanguages": [
    "English",
    "Marathi",
    "Hindi"
  ],
  "departmentId": 1
}
---
getName(empExample)

This script fails with following error -

26| getName(empExample)
    ^^^^^^^^^^^^^^^^^^^
Expecting Type: `Person`, but got: `Employee`.

 Reasons :
	- Close object does not allow additional properties.

	Function: `getName(p: `Person`) -> `String``
	Actual  : `getName(p: `Employee`)`

Person is represented as a closed subset of an Employee.

An explicit coercion of Employee to Person getName(empExample as Person) fails with following example -

Cannot coerce Object ({firstName: "Manik",lastName: "Magar",spokenLanguages: ["English", "Marathi",...) to Person

26| getName(empExample as Person)
            ^^^^^^^^^^^^^^^^^^^^
Trace:
  at main::getName (line: 26, column: 9)
  at main::main (line: 26, column: 1)

There are two ways to get this working -

  1. Manually map employee to Person - getName({firstName: empExample.firstName, lastName: empExample.lastName}).
  2. Change Person to be an open object - type Person = {firstName: String, lastName: String}, in which case getName(empExample) works.

Will it make sense to allow type casting objects into other if they are closed subsets - getName(empExample as Person)?

@jerneyio
Copy link
Contributor

I can think of another way to get this working w/ a union type. Would this alleviate the pain point you're experiencing?

fun getName(p : Person | Employee): String ...

Or you could overload

fun getName(p: Person): String ...

fun getName(p: Employee): String ...

@manikmagar
Copy link
Author

If I am using a custom utility module from shared resource that provides me many functions to handle Person object, I won't be able to use union types unless I modify that custom module.

I think those approaches will work if you have control over all types or they are known in advance.

@menduz
Copy link
Contributor

menduz commented Feb 21, 2021

Have you tried removing the "closed object" syntax?

-type Person = {| firstName: String, lastName: String |}
+type Person = { firstName: String, lastName: String }

fun getName(p:Person): String = "$(p.firstName) $(p.lastName)"

It should work for your use case.. In most cases, DataWeave have structural types. That means it won't pay attention to the name of the type but yes to the structure of the type. In this specific case, by using {| ... |} you are telling the type system to check that the type only has the properties you specify, nothing else is allowed. Instead, by using a type without the pipes { ... } you are telling the type system to use a type that matches, allowing extra properties.

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

No branches or pull requests

3 participants