So I'm building a data type where, I would like, optional auto-casting. The last question I asked is related to this also.
The code I currently have can be found below:
class Test(T)
##auto_cast = false
def initialize(var : T)
#var = var
end
def self.auto_cast
##auto_cast
end
def self.auto_cast=(val)
##auto_cast = val
end
def self.auto_cast(forced_value=true,&block)
#Force value, but store initial value:
ac = ##auto_cast
##auto_cast = forced_value
block.call
##auto_cast = ac
end
def +(val)
var = #var
if ##auto_cast
if var.is_a? String
casted_arg = val.to_s
return var + casted_arg
else
casted_arg = typeof(var).new(val)
return var + casted_arg
end
else
if typeof(var) != typeof(val)
{{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
else
return var + val
end
end
end
end
When I try to test the data type however:
Test.auto_cast do
puts Test.auto_cast
puts Test.new(1) + "1"
puts Test.new("1") + 1
end
It throws an error at return var + val:
if typeof(var) != typeof(val)
{{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
else
ERROR! --> return var + val
end
At first I was confused why, but now it makes sense.
I believe the Crystal compiler cannot be certain that ##auto_cast will be true whenever I intend to auto_cast (and to be fair, when auto-casting is disabled, I want the syntax error).
A compile error occurs because the value of ##auto_cast is unknown at compile time.
Due to the contradictory nature of the bodies:
.
if var.is_a? String
casted_arg = val.to_s
return var + casted_arg
else
casted_arg = typeof(var).new(val)
return var + casted_arg
end
and
if typeof(var) != typeof(val)
{{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
else
return var + val
end
Each definition should only be used when the user explicitly declares it. Thus this is more suited to a macro.
Given these reasons I started trying to build the functionality into a macro instead:
def +(val)
var = #var
{%if ##auto_cast%}
if var.is_a? String
casted_arg = val.to_s
return var + casted_arg
else
casted_arg = typeof(var).new(val)
return var + casted_arg
end
{%else%}
if typeof(var) != typeof(val)
{{raise "Error: Type of <<var>> is not equal to type of <<val>> while auto_cast is false."}}
else
return var + val
end
{%end%}
end
I thought this would work because, this way code is only ever generated if ##auto_cast is set. However what I forgot was premise #2. I.E. the value of ##auto_cast is unknown at compile time. Ultimately, in order to make this work I would need a variable which can be:
Set at compile time.
Used globally within macros at compile time.
Ultimately I figured I could do something along the lines of this:
SET_AUTOCAST_VARIABLE true
puts Test.auto_cast
puts Test.new(1) + "1"
puts Test.new("1") + 1
SET_AUTOCAST_VARIABLE false
and then in the +() definition:
{%if autocast_variable %}
...
{%else%}
...
{%end%}
The problem is, I do not think such a macro global variable exists... I was thinking about ways to get around this issue and so far the only solution I can come up with is using some external file at compile time:
{{File.write("/tmp/cct","1")}}
puts Test.auto_cast
puts Test.new(1) + "1"
puts Test.new("1") + 1
{{File.write("/tmp/cct","")}}
and in the method definition:
{%if File.read("/tmp/cct")=="1" %}
...
{%else%}
...
{%end%}
This feels really hacky though... I was wondering whether there were any other alternatives, (or, even, if this just won't work at all)?
This can't work. Methods are only instantiated once, it is not possible to have two implementations of the same method with the same argument types. In the following example both + methods will inevitably have the same implementation.
Test.auto_cast do
Test.new(1) + "1"
end
Test.new(1) + "1"
You can't have different implementations of the same method depending on lexical scope. The method is exactly instantiated once and so is the macro inside it.
I don't understand your overall use case, but maybe there are other ways to achieve what you need.
For completeness: You can utilize a constant as a macro global variable. Constants can't be redefined, but altered through macro expressions. That can be used to store state between macros. For example:
FOO = [true]
{{ FOO[0] }} # => true
{% FOO.clear; FOO << false %}
{{ FOO[0] }} # => false
That's pretty hacky, though ;)
Related
I created a simple code in Scala that checks whether an input is correctly formatted as HH:mm. I expect the code to result in an Array of valid strings. However, what I'm getting as a result is of type Any = Array(), which is problematic as when I try to print that result I get something like that:
[Ljava.lang.Object;#32a59591.
I guess it's a simple problem but being a Scala newbie I didn't manage to solve it even after a good few hours of googling and trial & error.
val scheduleHours = if (inputScheduleHours == "") {
dbutils.notebook.exit(s"ERROR: Missing param value for schedule hours.")
}
else {
val timePattern = """^((?:[0-30]?[0-9]|2[0-3]):[0-5][0-9])$""".r
val inputScheduleHoursParsed = inputScheduleHours.split(";").map(_.trim)
for (e <- inputScheduleHoursParsed) yield e match {
case timePattern(e) => e.toString
case _ => dbutils.notebook.exit(s"ERROR: Wrong param value for schedule hours: '${inputScheduleHours}'")
}
}
The problem is that some branches return the result you want and others return dbutils.notebook.exit which (I think) returns Unit. Scala must pick a type for the result that is compatible with both Unit and Array[String], and Any is the only one that fits.
One solution is to add a compatible value after the calls to dbutils.notebook.exit, e.g.
val scheduleHours = if (inputScheduleHours == "") {
dbutils.notebook.exit(s"ERROR: Missing param value for schedule hours.")
Array.empty[String]
}
Then all the branches return Array[String] so that will be the type of the result.
I use Lua in computercraft to automate the mining. But, my turtle whose program worked very well before, stops if it meets a lava/flowing_lava/water/flowing_water source.
Inside my program, I have a lot of function to manage, for example, the fuel management, the tunnel, the collision with gravel, and .. the detection if the turtle meets a "block".
If the block is just an air block, the turtle continues to advance, elseif the block isn't an air block, the turtle digs this block and doesn't move forward if there is still a block in front of her.
The problem? The four sources which I quoted previously are considered as blocks, and the turtle can't move forward.
I try to fix this problem with multi-condition into the if, but it's doesn't work, the turtle moves forward and dig in any direction.
So I think it's because my way of creating the if isn't good, maybe the syntax (for concatenating many or into () ).
How to solve this issue?
function blockDetection(position, justDetection)
success, detectionBlock = nil
block_name = ""
if position == "right" then
turtle.turnRight()
success, detectionBlock = turtle.inspect()
turtle.turnLeft()
if success then
block_name = detectionBlock.name
if justDetection == true and detectionBlock.name == "minecraft:air" then
block_name = true
elseif justDetection == true and detectionBlock.name ~= "minecraft:air" then
block_name = false
else
end
end
end
end
I think your problem is that you forgot to return block_name. If you omit the return statement, you implicitly return 0 arguments, so trying to access any would give nil values. For example
if blockDetection (position,justDetetcion) then --[[something]] end, would never execute the then-end block, since nil is considered false.
You should also one more thing you should change in your code:
You shouldn't use x==true. If x is a boolean, then if x==true then ... is equivalent to if x then ....
So, your code should look a like this:
function blockDetection(position, justDetection)
success, detectionBlock = nil
block_name = ""
if position == "right" then
turtle.turnRight()
success, detectionBlock = turtle.inspect()
turtle.turnLeft()
if success then
block_name = detectionBlock.name
if justDetection and detectionBlock.name == "minecraft:air" then
block_name = true
elseif justDetection and detectionBlock.name ~= "minecraft:air" then
block_name = false
else
end
end
end
return block_name
end
I have a 'wrapper function' that takes inputs and just runs a lot of functions in turn and spits out a result at the end. A simple example
function wrapper(a,b)
c = first_function(a,b)
d = second_function(c)
if typeof(d) == Int64
e = third_function(d)
f = fourth_function(e)
g = fifth_function(f)
try
h = sixth_function(g)
catch
i = "this has failed"
end
i = seventh_function(h)
else i = "this has failed"
end
return i
end
There are about 5 different places throughout the list of functions that I want to set up 'if - else' statements or 'try - catch' statements. The 'else' part and the 'catch' part are always evaluating the same things. In this example you can see what I mean by seeing that both the else and the catch statements execute i = "this has failed".
Is there a way that I can just define i = "this has failed" at the bottom of the function's code and just tell julia to skip to this line for the 'else' or 'catch' parts ? For example I'd like my above to be something like:
function wrapper(a,b)
c = first_function(a,b)
d = second_function(c)
if typeof(d) == Int64
e = third_function(d)
f = fourth_function(e)
g = fifth_function(f)
try
h = sixth_function(g)
catch
<skip to line 10>
end
i = seventh_function(h)
else <skip to line 10>
end
<line 10> i = "this has failed"
return i
end
You can use the #def macro from this SO post. For example:
#def i_fail_code begin
i = "this has failed"
end
and then you'd do:
function wrapper(a,b)
c = first_function(a,b)
d = second_function(c)
if typeof(d) == Int64
e = third_function(d)
f = fourth_function(e)
g = fifth_function(f)
try
h = sixth_function(g)
catch
#i_fail_code
end
i = seventh_function(h)
else #i_fail_code
end
return i
end
This macro is pretty cool because even though it's essentially just copy/pasting what's in its definition it will even get the line numbers for errors correct (i.e. it will send you to the correct line in the #def definition).
You got some great literal answers answering your literal question, but the real question is why do you need to do it like this in the first place? It sounds like a really bad design decision. Essentially you're reinventing the wheel, badly! You're trying to implement a "subroutine" approach as opposed to a "functional" approach; subroutines have all but disappeared decades ago, for good reason. The fact that your question essentially boils down to "GOTO for Julia" should be a really big red flag.
Why not just define another function that handles your "fail code" and just call it? You can even define the fail function inside your wrapper function; nested functions are perfectly acceptable in julia. e.g.
julia> function outer()
function inner()
print("Hello from inner\n");
end
print("Hello from outer\n");
inner();
end
outer (generic function with 1 method)
julia> outer()
Hello from outer
Hello from inner
So in your case you could simply define a nested handle_failure() function inside your wrapper function and call it whenever you feel like it and that's all there is to it.
PS: Preempting the typical "there are some legit uses for GOTO in modern code" comment: yes; this isn't one of them.
Julia has built in goto support via macros, which may be the simplest option. So something like:
function wrapper(a,b)
c = first_function(a,b)
d = second_function(c)
if typeof(d) == Int64
e = third_function(d)
f = fourth_function(e)
g = fifth_function(f)
try
h = sixth_function(g)
catch
#goto fail
end
i = seventh_function(h)
else
#goto fail
end
return i
#label fail
i = "this has failed"
return i
end
Also note that you almost never want to test the type of a variable in Julia - you should handle that by multiple dispatch instead.
Why does this output "html is empty"?
#h = {<br />}
#h match {
case Html("") => {html is empty}
case _ => {html has content}
}
and this outputs "html has content"?
#i = #{Html("<br />")}
#i match {
case Html("") => {html is empty}
case _ => {html has content}
}
The reason this matters to me is because in the common use cases last example (moreScripts and moreStyles equivalents), the first style is used to pass in a chuck of html into another template. I then want to switch based on if that html has content or not. But it always matches to Html("").
The code generated for each of the methods is slightly different.
def h:play.api.templates.Html = {
_display_(
Seq[Any](format.raw("""<br />"""))
)
}
def i = {{Html("<br />")}}
The _display_ method used in creating h ends up performing a foldLeft on all the elements of the passed in Seq
This results in:
Html("") + Html("<br />")
The Html case class turns out to be backed by a mutable StringBuilder.
case class Html(text: String) extends Appendable[Html] with Content with play.mvc.Content {
val buffer = new StringBuilder(text)
/**
* Appends this HTML fragment to another.
*/
def +(other: Html): Html = {
buffer.append(other.buffer)
this
}
override def toString = buffer.toString
/**
* Content type of HTML (`text/html`).
*/
def contentType: String = "text/html"
def body: String = toString
}
This means that the value of text is only ever going to be set to the value of the first Html's text value. Whenever you create a new Html via the + method you only modify the StringBuilder.
E.g.
val html = Html("1") + Html("2")
html.text == "1"
html.toString == "12"
html.body == "12"
Since it is the text value that is used for pattern matching this effectively breaks its ability to be used in pattern matching.
E.g.
(Html("1") + Html("2")) match { case Html("1") => "broken" } // returns "broken"
Maybe try doing a string match?
#h.toString() match {
case "" => {html is empty}
case _ => {html has content}
}
Consider this (very ugly code):
object ExternalReferences2 {
import java.util.regex._
implicit def symbol2string(sym: Symbol) = sym.name
object Mapping {
def fromXml(mapping: scala.xml.NodeSeq) = {
new Mapping(mapping \ 'vendor text,
mapping \ 'match text,
mapping \ 'format text)
}
}
case class Mapping(vendor: String,
matches: String,
format: String) extends PartialFunction[String, String] {
private val pattern = Pattern.compile(matches)
private var _currentMatcher: Matcher = null
private def currentMatcher =
{ println("Getting matcher: " + _currentMatcher); _currentMatcher }
private def currentMatcher_=(matcher: Matcher) =
{ println("Setting matcher: " + matcher); _currentMatcher = matcher }
def isDefinedAt(entity: String) =
{ currentMatcher = pattern.matcher(entity); currentMatcher.matches }
def apply(entity: String) = apply
def apply = {
val range = 0 until currentMatcher.groupCount()
val groups = range
map (currentMatcher.group(_))
filterNot (_ == null)
map (_.replace('.', '/'))
format.format(groups: _*)
}
}
val config =
<external-links>
<mapping>
<vendor>OpenJDK</vendor>
<match>{ """^(javax?|sunw?|com.sun|org\.(ietf\.jgss|omg|w3c\.dom|xml\.sax))(\.[^.]+)+$""" }</match>
<format>{ "http://download.oracle.com/javase/7/docs/api/%s.html" }</format>
</mapping>
</external-links>
def getLinkNew(entity: String) =
(config \ 'mapping)
collectFirst({ case m => Mapping.fromXml(m)})
map(_.apply)
def getLinkOld(entity: String) =
(config \ 'mapping).view
map(m => Mapping.fromXml(m))
find(_.isDefinedAt(entity))
map(_.apply)
}
I tried to improve the getLinkOld method by using collectFirst as shown in getLinkNew, but I always get a NullPointerException because _currentMatcher is still set to null
scala> ExternalReferences2.getLinkNew("java.util.Date")
Getting matcher: null
java.lang.NullPointerException
at ExternalReferences2$Mapping.apply(<console>:32)
at ExternalReferences2$$anonfun$getLinkNew$2.apply(<console>:58)
at ExternalReferences2$$anonfun$getLinkNew$2.apply(<console>:58)
at scala.Option.map(Option.scala:131)
at ExternalReferences2$.getLinkNew(<console>:58)
at .<init>(<console>:13)
at .<clinit>(<console>)
at .<init>(<console>:11)
at .<clinit>(<console>)
while it works perfectly with getLinkOld.
What is the problem here?
Your matcher is created as a side-effect in isDefined. Passing side effecting functions to routine such as map is usually a recipe for disaster, but this is not even what happens here. Your code requires isDefined to have been called just before apply is, with the same argument. That makes your code very fragile, and that is what you should change.
Clients of PartialFunction do not have to do follow that protocol in general. Imagine for instance
if (f.isDefinedAt(x) && f.isDefinedAt(y)) {fx = f(x); fy = f(y)}.
And here the code that calls apply is not even yours, but the collection classes', so you do not control what happens.
Your specific problem in getLinkNew is that isDefined is simply never called.The PartialFunction argument of collectFirst is {case m => ...}. The isDefined that is called is the isDefined of this function. As m is an irrefutable pattern, it is allways true, and collectFirst will always return the first element if there is one. That the partial function returns another partial function (the Mapping) which happens not to be defined at m, is irrelevant.
Edit - Possible workaround
A very light change would be to check whether a matcher is available and create it if it is not. Better, keep the entity string that has been used to create it too, so that you can check it is the proper one. This should make the side effect benign as long as there is no multithreading. But the way, do not use null, use Option, so the compiler will not let you ignore the possibility that it may be None.
var _currentMatcher : Option[(String, Matcher)] = None
def currentMatcher(entity: String) : Matcher = _currentMatcher match{
case Some(e,m) if e == entity => m
case _ => {
_currentMatcher = (entity, pattern.matcher(entity))
_currentmatcher._2
}
}
Edit again. Stupid me
Sorry, the so called workaround indeed makes the class safer, but it does not make the collectFirst solution work. Again, the case m => partial function is always defined (note: entity does not even appears in your getLinkNew code, which should be worrying). The problem is that one would need a PartialFunction of a NodeSeq (not of entity, which will be known to the function, but not passed as argument). isDefined will be called, then apply. The pattern and the matcher depends on the NodeSeq, so they cannnot be created beforehand, but only in isDefined and/or apply. In the same spirit, you can cache what is computed in isDefined to reuse in Apply. This is definitely not pretty
def linkFor(entity: String) = new PartialFunction[NodeSeq, String] {
var _matcher : Option[String, Matcher] = None
def matcher(regexp: String) = _matcher match {
case Some(r, m) where r == regexp => m
case None => {
val pattern = Pattern.compile(regexp)
_matcher = (regexp, pattern.matcher(entity))
_matcher._2
}
}
def isDefined(mapping: NodeSeq) = {
matcher(mapping \ "match" text).matches
}
def apply(mapping: NodeSeq) = {
// call matcher(...), it is likely to reuse previous matcher, build result
}
}
You use that with (config \ mapping).collectFirst(linkFor(entity))