Refactorings in GoLand: Change Signature
Today, we’re going to start a series of blog posts about an essential part of the development life cycle that happens for any code we write — refactoring.
Thanks to the automation in the IDE, we can perform a lot of refactoring operations in a safe, automated, manner.
As of 2018.3, the following refactoring features are available to use in GoLand are:
- Rename
- Move & Copy
- Extract variable/constant
- Extract function/method
- Inline variable/constant
- Change Signature
- Extract Interface (new in 2019.1)
Below I am going to talk about a single one, the Change Signature refactoring, with the rest of the refactorings to be discussed in follow-up articles. This feature is new in 2018.3, a version at the time of writing still in the Early Access Program (EAP) stage. A quick description of what EAP stands for can be found in this previous blog post, and you can start using it today.
I chose this refactoring not only because it’s the newest member of the refactorings family, but also because it’s quickly becoming one of those I use most frequently as I code.
I also love the power that the Move refactoring offers, especially when moving a symbol across packages, but I use Move refactoring less often than I write function/method declarations or calls.
As for the other refactoring features, I will cover each of those in separate future articles.
Now let’s see this in action and how I typically use it. Consider the following code for example:
package main import "fmt" type Person struct { ID int Name string } func (p *Person) String() { fmt.Printf("Person:\n\tID:\t%d\n\tName:\t%s\n", p.ID, p.Name) } func NewPerson(id int, name string) *Person { return &Person{ID: id, Name: name} } func main() { person := NewPerson(1, "Florin") fmt.Printf("person: %v\n", person) }
Now, let’s say I want to add a new parameter to the ` NewPerson() ` function.
Until now, the usual steps were:
- Go to the function declaration site
- Change the signature there
- Go back to where I was editing and change the function call
- Go back to the function and use the Find Usages feature to discover if the function is used anywhere else in the code. Alternatively, execute a Run configuration and wait for the compiler to complain about the signatures being mismatched
With the new refactoring in place, I can use the shortcut for Change Signature (CTRL+F6 on Windows / Linux and CMD+F6 on Mac) on the function call ` NewPerson(1, “Florin”) ` and add a new parameter to the function.
When adding a new parameter, we can also add a default value for it or default to the zero value, so that when the IDE processes the usages of this function it will also automatically add that value as well.
Let’s see it in action:
While I’m using a constant value in the example, you can also have an expression as a default value for the new parameter type.
The new workflow helps me save time as I don’t need to manually run any search and replace, use some very advanced command line scripting, or have to wait for the compiler to tell me what went wrong.
And it all happens at the call site I am currently at, which means I don’t have to switch contexts and I can focus on writing code as before, then go back and fill the implementation detail. Of course, you can invoke the refactoring at the declaration site as well, with the same results.
Furthermore, not only can I add or remove parameters, but I can also change their order or rename them too. Let’s say I notice that it’s better to call the function like this ` NewPerson(“Florin”, 1, false) ` instead of the current way of doing it.
I can use the Change Signature refactoring once again to swap the parameter places as I need them to be, and the IDE will take care of automatically swapping up the values at the call site.
Aside from the above changes to a function or method signature, the Change Signature refactoring is also useful for adding/removing return values.
Like with the other refactoring features, I can also preview what’s about to happen to the code, before applying any refactoring. That way I can observe all the affected paths and even remove some of them which should not be automatically touched by the IDE.
And if I change my mind, the Undo operation will atomically undo all the changes made by the IDE in one quick move.
This way, my coding speed has improved, thanks to the automation that the IDE provides, as well as having to switch the context less to be able to implement the changes I need.
That’s it for today. I hope you liked this article and I’m looking forward to your feedback on this feature. Let us know what you would like to see next from us — both here on the blog and in the IDE itself. Please add your feedback in the comment section below, on our issue tracker, on Twitter, or any other channel that you are comfortable with.