How to use Optional in Netlogo Extensions - scala

I want to create a netlogo primitive that may receive a boolean or may not. Therefore I want make possible to the user that he uses the primitive of these two ways:
1:
ask Walkers [
qlearningextension:learning
]
2:
ask Walkers [
qlearningextension:learning true
]
I tried to do that with OptionalType, but I could not make it. Is it possible to do what I want? If so, how can I do it?

So OptionalType unfortunately only works with CommandBlockType. For a good example of how that works, check out the sample-scala extension (maybe that's where you saw a reference to it in the first pace). OptionalType will not work with BooleanType.
There is a secondary option, that's a little hacky. You can use RepeatableType along with setting defaultOption and minimumOption in your syntax (so NetLogo knows that 0 arguments is okay/expected). Scala code example:
object RepeatableTypeTest extends api.Command {
override def getSyntax =
commandSyntax(
right = List(BooleanType | RepeatableType),
defaultOption = Some(0),
minimumOption = Some(0)
)
def perform(args: Array[api.Argument], context: api.Context) {
println(args.length)
if (args.length > 0) {
val ref = args(0).getBoolean
println(ref)
} else {
println("No argument given!")
}
}
}
Then you just have to wrap calls with the boolean argument in parenthesis, so NetLogo knows you're not starting a new command (it expects the defaultOption without the parens):
to test
sample-scala:rep-bool
(sample-scala:rep-bool true)
(sample-scala:rep-bool false)
(sample-scala:rep-bool false true false true false)
end
The problem with this, as you can see in the example, is if your users want to they can provide extra useless booleans: (sample-scala:rep-bool false true false false true false false). If your code ignores them they won't have an effect, but they could be confusing or weird to extension users.

Related

Return keyword inside the inline function in Scala

I've heard about to not use Return keyword in Scala, because it might change the flow of the program like;
// this will return only 2 because of return keyword
List(1, 2, 3).map(value => return value * 2)
Here is my case; I've recursive case class, and using DFS to do some calculation on it. So, maximum depth could be 5. Here is the model;
case class Line(
lines: Option[Seq[Line]],
balls: Option[Seq[Ball]],
op: Option[String]
)
I'm using DFS approach to search this recursive model. But at some point, if a special value exist in the data, I want to stop iterating over the data left and return the result directly instead. Here is an example;
Line(
lines = Some(Seq(
Line(None, Some(Seq(Ball(1), Ball(3))), Some("s")),
Line(None, Some(Seq(Ball(5), Ball(2))), Some("d")),
Line(None, Some(Seq(Ball(9))), None)
)),
balls = None,
None
)
In this data, I want to return as like "NOT_OKAY" if I run into the Ball(5), which means I do not need to any operation on Ball(2) and Ball(9) anymore. Otherwise, I will apply a calculation to the each Ball(x) with the given operator.
I'm using this sort of DFS method;
def calculate(line: Line) = {
// string here is the actual result that I want, Boolean just keeps if there is a data that I don't want
def dfs(line: Line): (String, Boolean) = {
line.balls.map{_.map { ball =>
val result = someCalculationOnBall(ball)
// return keyword here because i don't want to iterate values left in the balls
if (result == "NOTREQUIRED") return ("NOT_OKAY", true)
("OKAY", false)
}}.getOrElse(
line.lines.map{_.map{ subLine =>
val groupResult = dfs(subLine)
// here is I'm using return because I want to return the result directly instead of iterating the values left in the lines
if (groupResult._2) return ("NOT_OKAY", true)
("OKAY", false)
}}
)
}
.... rest of the thing
}
In this case, I'm using return keyword in the inline functions, and change the behaviour of the inner map functions completely. I've just read somethings about not using return keyword in Scala, but couldn't make sure this will create a problem or not. Because in my case, I don't want to do any calculation if I run into a value that I don't want to see. Also I couldn't find the functional way to get rid of return keyword.
Is there any side effect like stack exception etc. to use return keyword here? I'm always open to the alternative ways. Thank you so much!

Walk through all tree nodes?

I'm using py-tree-sitter and this code to walk the entire node tree in sequence (code is from this github issue: https://github.com/tree-sitter/py-tree-sitter/issues/33#issuecomment-864557166):
def traverse_tree(tree: Tree):
cursor = tree.walk()
reached_root = False
while reached_root == False:
yield cursor.node
if cursor.goto_first_child():
continue
if cursor.goto_next_sibling():
continue
retracing = True
while retracing:
if not cursor.goto_parent():
retracing = False
reached_root = True
if cursor.goto_next_sibling():
retracing = False
for node in traverse_tree:
print(node)
I'm using this code for syntax highlighting and this method does not give empty tokens like whitespace and newline which are not part of another AST token.
Is this the correct way to get all the nodes in the tree?
Thanks
Another solution is to use recursion. For example, since tree-sitter does not support query syntax for missing nodes yet, one possible solution to still get them:
missing_nodes = []
def traverse_tree(node: Node):
for n in node.children:
if n.is_missing: missing_nodes.append(n)
traverse_tree(n)
traverse_tree(tree.root_node)

Fastlane set options auto value

I would like to submit my lane with optional options. So for example the lane:
lane :mylane do |options|
mailgun(
to: "#{options[:mailto]}"
....
)
end
How do I give :mailto a default value? So if I would run fastlane mylane it would automatically set :mailto to mail#example.com.
But if I would runfastlane mylane mailto:"secondmail#example.com" it would use that value
As Lyndsey Ferguson pointed out in a comment on this answer, the following is simplest:
mail_addr = options.fetch(:mailto, 'mail#example.com')
where the first parameter of fetch is the option to fetch, and the second is the default value if the option was not passed in.
I just want to add that this works a lot better than the other suggestion:
options[:mailto] || 'mail#example.com'
when dealing with boolean options.
Fastlane (or maybe Ruby) interprets true, false, yes, and no as boolean values instead of strings (maybe others too, though I tried N, n, NO, and FALSE and they were treated as strings), so if in your lane implementation you had:
options[:my_option] || true
or
(options[:my_option] || 'true') == 'true'
you would get unexpected behaviour.
If you didn't pass in myOption at all, this would default to true as you would expect. If you passed in true this would also return true. But if you passed in false this would turn into true, which you of course wouldn't want.
Using options.fetch(:myOption, true) works great with boolean flags like the ones mentioned above and therefore seems better to use in general.
Here's a very thorough example in case you want to test it yourself:
lane :my_lane do |options|
puts("You passed in #{options[:my_option]}")
my_option = options[:my_option] || true
if my_option
puts('Using options[:my_option], the result is true')
else
puts('Using options[:my_option] the result is false')
end
my_option_fetched = options.fetch(:my_option, true)
if my_option_fetched
puts('Using fetched, the result is true')
else
puts('Using fetched, the result is false')
end
end
Outputs:
fastlane my_lane my_option:true
You passed in true
Using options[:my_option], the result is true
Using fetched, the result is true
fastlane my_lane my_option:false
You passed in false
Using options[:my_option], the result is true
Using fetched, the result is false
fastlane my_lane my_option:no
You passed in false
Using options[:my_option], the result is true
Using fetched, the result is false
Note, e.g. FALSE would default to true as it is not being interpreted as a boolean, which seems reasonable to me.
(Fastlane 1.77.0, Ruby 2.7.2)
EDIT: It's worth noting that if you pass an empty string instead of nothing/null you would not get the default value from the fetch method.
I'm not sure there's a way to make Fastlane pass a default. The processing is pretty simple:
https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/command_line_handler.rb#L10
But you can easily do this in your Fastfile:
lane :mylane do |options|
mail_addr = options[:mailto] || "mail#example.com"
mailgun(
to: "#{mail_addr}"
....
)
end

understanding why swift code won't work correctly

I'm new to coding and currently teaching myself swift using swift playgrounds on the iPad. My code runs and completes the puzzle but it continues to loop and I don't know why. I can't find any way to correct this code. Although I have found videos on YouTube with various code written differently. I don't just want to copy it though. I want to understand why this isn't working. I can send a video of the puzzle if needed.
while !isOnGem || !isOnClosedSwitch {
moveForward()
if isBlocked && !isBlockedRight {
turnRight()
}
if isBlocked && isBlockedRight {
turnLeft()
}
if isOnGem {
collectGem()
}
if isOnClosedSwitch {
toggleSwitch()
}
}
Without any other information regarding the functions in each of your if blocks, I'd say that it is due to your boolean values for isOnGem and isOnClosedSwitch. If the function collectGem() does not change the value of isOnGem to the opposite of what it was initially set to (true or false) and toggleSwitch() doesn't change the value of isOnClosedSwitch to the opposite of it's original value then you will be stuck in the loop. Since the loop will run "while" at least one of those values remain unchanged.
I believe adding a isOnGem = false and isOnClosedSwitch = false to their respective if blocks will be the solution.
You are missing the exit condition. while !isOnGem || !isOnClosedSwitchwill continue to loop as long as either condition is true, therefore your exit condition will be having both values set to false.
Note that both Booleans are inverted in your check so to make both conditions false you have to set the Booleans to true.
Since you code runs and yet does not exit to loop, you will want to check for changes to isOnGem and isOnClosedSwitch there might be one of the two that is always false resulting in the loop not exiting or the function that runs after each checks might have reset them to false
check for code like:
func collectGem(){
...
isOnGem = false
...
}
or one of the functions might not even have run, you can log each function like :
func toggleSwitch() {
print("toggleSwitchRunning")
}
and if "toggleSwitchRunning" did not print into the console, check that the condition that set isOnClosedSwitch to true is working properly

How do I avoid Stack Overflow with circular references in Backbone.js?

Two attributes in my model are supposed to update each other when changed, once. The startDate and endDate. Their values are Moment objects, from the moment.js library.
Two Moment objects of identical dates are not equivalent, and so this causes an loop that exceeds the maximum stack, because they appear to Backbone to have always changed.
new moment('01/01/12') == new moment('01/01/12') // => false
The { silent: true } option seems not to help, I think because it only defers the change event rather than suppressing it alltogether, though I'm not sure.
Here's the code that overflows:
class Paydirt.Models.BlockBrowser extends Backbone.Model
initialize: =>
#on('change:startDate', #updateEndDate)
#on('change:endDate', #updateStartDate)
updateStartDate: =>
#set({ startDate: #cloneEndDate().subtract('days', #get('interval')) }, { silent: true }
updateEndDate: =>
#set({ endDate: #cloneStartDate().add('days', #get('interval')) }, { silent: true } )
cloneStartDate: => new moment(#get('startDate'))
cloneEndDate: => new moment(#get('endDate'))
I can set a global flag to prevent the callback loop as in this variation:
updateStartDate: =>
if !#changing
#changing = true
#set({ startDate: #cloneEndDate().subtract('days', #get('interval')) }, { silent: true } )
#changing = false
updateEndDate: =>
if !#changing
#changing = true
#set({ endDate: #cloneStartDate().add('days', #get('interval')) }, { silent: true } )
#changing = false
... but this is obviously a hackety solution. Is there a better pattern for me to follow in this use case?
Thank you.
Another idea:
Are you using Backbone v0.9.2? it looks like it is doing a more intensive use of the options.silent. Look here.
The options.silent behavior you're describing looks more like v0.9.1.
Two ideas:
Overwrite the Underscore method _.isEqual to manage properly your Moment objects. You can use the Proxy pattern.
Use custom events to have more control that when they are triggered.
I'm not sure how to do this in backbone, but you can compare the integer value of the moments
(moment().valueOf() === moment().valueOf()) // true
or
(+moment() === +moment) // true