Setter method (assignment) with multiple arguments
Due to the syntax sugar of methods whose names end in=
, the only way that you can actually pass multiple parameters to the method is to bypass the syntax sugar and use send
…
h.send(:strategy=, :mystrategy, :backward )
…in which case you might as well just use a normal method with better names:
h.set_strategy :mystrategy, :backward
However, you could rewrite your method to automatically un-array the values if you knew that an array is never legal for the parameter:
def strategy=( value )
if value.is_a?( Array )
@strategy << value.first
@strategy.direction = value.last
else
@strategy = value
end
end
This seems like a gross hack to me, however. I would use a non-assigment method name with multiple arguments if you need them.
An alternative suggestion: if the only directions are :forward
and :backward
what about:
def forward_strategy=( name )
@strategy << name
@strategy.direction = :forward
end
def reverse_strategy=( name )
@strategy << name
@strategy.direction = :backward
end
Passing multiple parameters to Setter method using assignment expression
Separating values by comma without enclosing then in square brackets - []
- in Python, actually creates a tuple, not a list.
In fact, due to dynamic typing in Python, it is not considered a good practice to check exactly for a "list", when any sequence, or even iterable, will work equally well.
The second thing is that properties are meant to enable a single argument passing. Only the param
parameter in your function will be used - the second parameter, use_type
will not be passed by the property
mechanism.
That means you have to read your arguments explicitly inside your method code, and a little extra logic is needed so that use_type is actually optional.
Actually, if you want to parametrize the settings of tokens
with more than an argument, my advice would be to, in this case, just use a plain setter method, instead of resorting to properties or other descriptors. This will cause less surprise for people viewing (or having to write) code that use this class and set .tokens
:
class Question:
...
def __init__(self, ...):
self.token = ... # Plain, unguarded attribute
..
def set_token(self, value, use_type = None):
...
But if you really want a property that will accept a sequence, with the second value being optional. However, if you are really using typing annotations and enforcing then, you have to restrict your params to tuples (which fortunately is the data type created by Python when you just separate objects by ,
as is in your code)
class Question:
...
@token.setter
def token(self, params: typing.Tuple[typing.Any, typing.Optional[bool]):
"""params should be a 1-or-2 tuple, with the second item, if present
a bool indicating "use_type"
"""
# The operation bellow will raise TypeError
# if params is not a tuple, so no need for the explicit check -
# just let the error propagate
value, use_type, *_ = params + (False,)
# if only one item is passed, "False" ends up in "use_type".
# With 2 itens, the extra "False" is assigned to "_" indicating
# it should be disregarded (it is a Python convention for '_' as a variable name)
if use_type:
...
And with this your question.tokens = tokens, True
expression will work, as willquestion.tokens = tokens,
, but not question.tokens = tokens
- as in this case, the value is not a tuple; (if it is a tuple it will be incorrectly used inside the method body as is) - I will say again that this is a strange pattern, and an explicit setter method should be preferred.
Creating a setter method that takes extra arguments in Ruby
It doesn't work because the parser doesn't allow it. An equals sign is allowed in expressions of the form identifier = expression
, expression.identifier = expression
(where identifier is \w+
), expression[arguments] = expression
and expression.[]= arguments
and as part of a string or symbol or character literal (?=
). That's it.
gen.send(:allow=, 'a', 1, false)
would work, but at that point you could as well just give the method a name that doesn't include a =
.
Property setter with multiple values
How do I pass two values to the setter?
You can pass an iterable(tuple, list) to the setter, for example:
class A(object):
def __init__(self, val):
self.idx = val
@property
def idx(self):
return self._idx
@idx.setter
def idx(self, val):
try:
value1, value2 = val
except ValueError:
raise ValueError("Pass an iterable with two items")
else:
""" This will run only if no exception was raised """
self._idx = sha512(value1+value2)
Demo:
>>> a = A(['foo', 'bar']) #pass a list
>>> b = A(('spam', 'eggs')) #pass a tuple
>>> a.idx
<sha512 HASH object @ 0xa57e688>
>>> a.idx = ('python', 'org') #works
>>> b.idx = ('python',) #fails
Traceback (most recent call last):
...
raise ValueError("Pass an iterable with two items")
ValueError: Pass an iterable with two items
Multiple Parameters for Object.defineProperty Setter Function?
Is it possible to have multiple parameters for Object.defineProperty setter function?
Yes, but it's not possible to invoke them (other than Object.getOwnPropertyDescriptor(obj, "joe").set(null, false)
). A setter is invoked with the one value that is assigned to the property (obj.joe = "doe";
) - you cannot assign multiple values at once.
If you really need them (for whatever reasons), better use a basic setter method (obj.setJoe(null, false)
).
Kotlin setter with multiple arguments
That's not possible due to the way that setter functions work - they only take a single argument. Even if you think about the usage of a setter with multiple arguments, it wouldn't look right:
x.data = items, { /** listener impl */ }
If you really wanted to, you could group your arguments into a single object:
x.data = Wrapper(items, { /** listener impl */ })
But even that suggestion isn't nice. The nicest in my opinion is what you consider to be inelegant, using a Java style setter (which isn't a typical setter since it has multiple arguments), but at least Kotlin gives you a nicer call syntax:
x.setData(items) { /** listener impl */ }
Ruby, how to overwrite the setter ( = ) method to allow 2 parameters?
As @eugen correctly says, you cannot pass two arguments to a setter like
self.my_vector = 1, 2
The nearest thing you can achieve is to unpack the argument using pattern matching:
def myvector=(arg)
arg => [x, y]
@my_vector = Vector2d.new(x, y)
end
foo.my_vector = [1, 2]
An alternative is to define a simple helper method v
so you can write
foo.my_vector = v 1, 2
Why use setter when you can assign massively using a method?
Typically, the targets of getters and setters are made private so they're not directly accessible from outside of the file or library.
class Business {
String name, _address;
double lat, long;
bool coordsCalculated = false;
Map propertyRecords = {};
get address {
return _address;
}
set address(String address) {
if (address == _address) return; // Nothing changed;
_address = address;
// API call to calculate lat/log
APICall(onSuccess: (data) {
lat = data.lat;
long = data.long;
coordsCalculated = true;
});
}
void rewrite(String name, String address) {
this.name = name;
this.address = address;
}
String summary() {
if (coordsCalculated) return "Business name is $name, here's a link to the map!";
return "Business name is $name, at $_address.";
}
Human(this.name, String address) {
this.address = address;
}
}
The user of the class feels like they're using a normal property, but it does other silent things.
Methods can do this too, yes, but this can feel cleaner.
Importantly, getters and setters cannot be asynchronous which definitely can give methods an advantage, but there are plenty of valid uses.
Getters and setters are also easier to read, when being used. Less parentheses are always a good thing.
You certainly don't need to always use them, or use them when they do nothing but set the variable, but they can be nice.
In one of my Widgets, I have a getter that looks something like
FileState get fileState => FileUploaderKey.currentState!. widget.file.state;
It's so much easier to read this way. It gets the current state of the file, always, whereas
FileState fileState = FileUploaderKey.currentState!.widget.file.state;
Only saves the current state, but doesn't change with it.
Related Topics
Create Custom HTML Helpers in Ruby on Rails
Reading and Updating Yaml File by Ruby Code
Generate an HTML Table from an Array of Hashes in Ruby
Creating Permutations from a Multi-Dimensional Array in Ruby
Detect If Application Was Started as Http Server or Not (Rake Task, Rconsole etc)
Is There a Cucumber Hook to Run Before and After Each Feature
How to Identify Aliased Methods in Ruby
Replace Words in a String - Ruby
Loaderror Running Mongrel with Rails3 and Ruby 1.9.2
Xpath Expression for Regex-Like Matching
How to Install Redcloth on Windows
How to Validate Xhtml with Nokogiri
Getting Uninitialized Constant Error When Trying to Run Tests