question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Object destructuring in method calls

See original GitHub issue

Hi

I want to propose an idea, allow destructing object over method invocation for avoid write “paramName = obj.paramName

Let me show you it with an example:

class Person(shared String lastName, shared String firstName, shared Integer birthYear){}

Person smith = Person("Smith", "John", 1985);

We want to create a copy modifying the birthYear for doing it we can create a copy method in the Person class, or create a new copy using the constructor.

Using the copy method design pattern: This design requires write a special method for create a new copy, maybe in a future the compiler can generate it automatically in some cases:

class Person_(shared String lastName, shared String firstName, shared Integer birthYear){
    shared Person_ copy(String lastName = this.lastName, String firstName = this.firstName, Integer birthYear = this.birthYear) {
        return Person_(lastName, firstName, birthYear);
    }
}

Person_ smith_ = Person_("Smith", "John", 1985);
Person_ copy_ = smith_.copy{birthYear = 1980;};

Another approach is create a new copy using a constructor

Person copy1 = Person(smith.lastName, smith.firstName, 1980); // Parameter positional invocation
Person copy2 = Person { // Parameter named invocation
    lastName = smith.lastName;
    firstName = smith.firstName;
    birthYear = 1980;
};

My proposition is to allow destructing object in the method invocation

Person copy = Person { // Parameter named invocation
    ...smith; // Unsupported syntax at this moment inspired in the object spread in EcmaScript 7
    birthYear = 1980;
};

In this way we can create copies of simple objects without needed of a copy method in a easy way.

Rules: The method take from the destructed object the properties with the same name and compatible type missing in the method invocation

Syntax: Two options:

  • As is in lower span. Eg: ...smith
  • As in spread operator. Eg.: *smith

I prefer the span syntax because the spread syntax can be confused with an spread argument

Thanks!

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
jvasileffcommented, Feb 1, 2017

This could be made a bit more general than just “spread an object into the constructor of the same class”

I agree. And, spreading of labels tuples (#3851) for all named argument invocations.

While cloning with changes is important, it covers only a fraction of the potential use cases for spreading name->value mappings. This is especially true in Ceylon which favors immutability and null safety. 1) you can’t rely on mutability to populate fields using reusable functions that operate on superclasses, and 2) you can’t easily create “template” instances of a class that have only a few populated fields.

An example: construct both Employees and Customers using common code for their common fields (they’d likely be subclasses of sealed abstract Person, but that doesn’t help us).

Today, you’d wind up with a bunch of code duplication:

value personDetails = getPersonDetails(id);
if (isEmployee) {
    return Employee {
        id = personDetails.id;
        lastName = personDetails.lastName;
        firstname = personDetails.firstname;
        birthYear = personDetails.birthYear;
        department = lookupDept(id);
        salary = lookupSalary(id);
    };
}
else if (isCustomer) {
    return Customer {
        id = personDetails.id;
        lastName = personDetails.lastName;
        firstname = personDetails.firstname;
        birthYear = personDetails.birthYear;
        firstPurchaseDate = lookupFPD(id);
    };
}

with mutability (non-Ceylonic):

if (isEmployee) {
    value employee = Employee(id);
    fillInPersonDetails(employee);
    employee.department = lookupDept(id);
    employee.salary = lookupSalary(id);
    return employee;
}
else if (isCustomer) {
    value customer = Customer(id);
    fillInPersonDetails(customer);
    customer.department = lookupDept(id);
    customer.salary = lookupSalary(id);
    return customer;
}

and with flexible named argument spreading, you might have:

if (isEmployee) {
    return Employee {
        *getPersonDetails(id);
        department = lookupDept(id);
        salary = lookupSalary(id);
    };
}
else if (isCustomer) {
    return Customer {
        *getPersonDetails(id);
        firstPurchaseDate = lookupFPD(id);
    };
}

I think the last example provides all of the benefits of Ceylon’s null safety and immutability, and the code reuse benefits currently only available with Java bean style mutability. This would be even better with #3851.

Though this might cause problems when the type to be spread evolves to have more shared attributes

I tend to think that is an acceptable risk, and would only affect cases where the type’s new attribute has the same name and type as a defaulted parameter, and an argument for that parameter is not otherwise provided.

0reactions
ChristopheLscommented, Oct 14, 2016

Person { *person; birthYear = 1980; } does not resolve inheritance issues (this almost clone feature has the sames issues as clone 260

shared class VIP(String lastName, String firstname, Integer birthYear, shared Integer followers)
    extends Person(lastName, firstname, birthYear) {`
}
Person agent007 = VIP("bond", "james", 1950, 2000);
Person younger = agent007.copy{ birthYear = 1990; } ; // this should return a VIP instance

while

Person { *agent007; birthYear = 1980; }

create an instance of class Person.

In Java, i use the builder pattern with a cloneBuilder method that return a builder instance with copies values of “this” ; but it’s very heavy and verbose style.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Object destructuring for function calls - javascript
One option is to use .map to extract the value of each property you want, and spread it into the argument list: someFunction(...
Read more >
Destructuring assignment - JavaScript - MDN Web Docs
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, ...
Read more >
Destructuring Mixed Objects and Function Arguments in ES6
Object destructuring is a useful JavaScript (ECMAScript 6) feature to extract properties from objects and bind them to variables.
Read more >
Extract Functions Arguments using Destructure in JavaScript
Destructuring is terrific at extracting value from your arguments. So swap out those bracket ... In every function, there is a built-in arguments...
Read more >
Destructuring assignment - The Modern JavaScript Tutorial
The two most used data structures in JavaScript are Object and Array . ... Although, when we pass those to a function, it...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found