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

Explicit documentation of mutable function parameters #9741

Closed
danvk opened this issue Jul 14, 2016 · 9 comments
Closed

Explicit documentation of mutable function parameters #9741

danvk opened this issue Jul 14, 2016 · 9 comments
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds

Comments

@danvk
Copy link
Contributor

danvk commented Jul 14, 2016

JavaScript makes it easy to mutate Object parameters:

interface User {
    name: string;
    age: number;
} 
function foo(user: User) {
    user.age = 32;
}

Mutating an argument is somewhat unusual, so mutable parameters are typically documented in comments. But it would be better if this documentation were part of the function declaration, ala const in C++. That way inadvertent mutations could be caught with tsc.

For example:

function bad(user: User) {
  user.age = 32;  // error: user is immutable
}
function ok(mutable user: User) {
  user.age = 32;  // ok
}

To preserve compatibility, function parameters would all be mutable by default unless a new strictMutableChecks flag were set.

Scalar parameters could always be modified, since these changes wouldn't be visible outside the function:

// with strictMutableChecks=true
function foo(x: number): number {
  x += 1;  // ok; not visible outside of foo().
  return x;
}

There would have to be some way for declaration files to indicate whether they were explicitly documenting mutable parameters or using the standard mutable-by-default.

It would also be nice if there were a way to mark constants as immutable. This could help catch whole classes of bugs, e.g. forgetting that _.extend mutates its first parameter in addition to returning a combined Object:

declare module _ {
  'strictMutableChecks';  // Make parameters read-only by default in this module.
  function extend(mutable destination: any, ...sources: any[]): any;
}

const readonly BASE_STYLE = {
  font: 'Times',
  fontWeight: 'bold'
};

const myStyle = _.extend(BASE_STYLE, { font: 'Comic Sans' });  // error: BASE_STYLE is readonly
// should be: _.extend({}, BASE_STYLE, { font: 'Comic Sans' });

This is related to #7770 but is less ambitious, since it would only apply to function parameters.

It may be related to #8575 but there's not much context there.

@poke
Copy link

poke commented Jul 19, 2016

It’s difficult (if not impossible?) to detect mutation though. Think about this:

function doSomething(user: User) {
    user.updateSomething();
}

Here, updateSomething() would modify the user object, requiring the user argument to be “mutable”. In order to track that, updateSomething would require some information that it updates the object. While this might still be possible, it gets really complicated if updateSomething does not mutate user directly but mutates an object that exists as a member on user.

@danvk
Copy link
Contributor Author

danvk commented Jul 19, 2016

@poke Classes are tricky for sure. There could be a way to mark that method as mutating the class in the definition of User. Perhaps:

class User {
  mutable updateSomething() { ... }
}

Unless TypeScript could infer that the updateSomething method mutates this, it would have to assume that it doesn't, much as function parameters are assumed to have an any type unless TS can deduce something more precise.

In other words: I think this is analogous to optional typing. If you pass an immutable parameter to a function which mutates it, that's unfortunate. But you're no worse off than in plain JS. But if TS knows that it will mutate it, it can warn you. And that's tremendously helpful!

@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Jul 19, 2016
@mhegazy
Copy link
Contributor

mhegazy commented Jul 19, 2016

We have discussed in the past supporting const on function parameters.

@danvk
Copy link
Contributor Author

danvk commented Jul 21, 2016

@mhegazy were there any conclusions? Having a way to make parameters const-by-default would make this a more useful check, but it would be a more radical change.

@mhegazy
Copy link
Contributor

mhegazy commented Jul 21, 2016

I do not think making arguments immutable by default is an option. You can always have a lint rule to make all parameters immutable if you so chose.

@ethanresnick
Copy link
Contributor

Related/context: #9998

@SamuelMarks
Copy link

Bumping this issue as making argument explicitly const would be useful. Even if it were fake in the way const is already (see const vs Object.freeze for example).

@RyanCavanaugh RyanCavanaugh added Too Complex An issue which adding support for may be too complex for the value it adds and removed In Discussion Not yet reached consensus labels Aug 12, 2017
@RyanCavanaugh
Copy link
Member

We're investigating behavior like this as part of a larger effort. See #17502 for some preliminary notes, but closing this one for housekeeping purposes since the overall readonly picture will be more all-encompassing (if it happens). For backcompat purposes, mutable would likely be the default and you'd need to opt in to readonly

@wizarrc
Copy link

wizarrc commented Aug 30, 2017

We have discussed in the past supporting const on function parameters.

@mhegazy What is the status on that discussion? Is there an issue being tracked? I was going to open a new issue till I searched and found this topic. The link mentioned above covers mostly immutable/mutable stuff but not shallow immutable like const. I really want something in the lines of this:

function(const index: number) {
  index++; // Same compile error message as declaring a new const inside the body
}

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds
Projects
None yet
Development

No branches or pull requests

7 participants