I don't know all Swift mechanics, and how it handles variables.
I always preferred to declare variables before entering a for or while loop, not matter the language, rather than declaring them inside the loop over and over.
But is it that bad to re-declare variables ? Would it affect performance with a very large iteration ? How does specifically Swift handle this behavior ?
example :
while i < 100 {
let a = someFunc()
i += 1
}
VS
let a: MyObj
while i < 100 {
a = someFunc()
i += 1
}
This would not impact performance, and version 1 is highly preferred. Even if it would impact performance, you would need to demonstrate that on your precise code before you would consider any other option but version 1. There are no universal performance answers when dealing with an optimizing compiler. Doing anything unusual "for performance" that you have not deeply explored with your code runs a high likelihood of making things worse. The normal cases are the most optimized cases.
(I know I'm overstating this. There are definitely ways to look at code and say "that's going to be horribly inefficient." And there are some quirky parts of Swift where things that look ok are in fact bad, most notably using + to combine strings, or using pre-Swift4 reduce to create an array. But in the cases that those matter, you're going to discover it really quickly because they're really bad when they matter.)
But we don't have to guess about any of this. We can just ask the compiler.
// inside.swift
import Foundation
func runme() {
var i = 0
while i < 100 {
let a = Int.random(in: 0...10)
print(a)
i += 1
}
}
// outside.swift
import Foundation
func runme() {
var i = 0
var a: Int
while i < 100 {
a = Int.random(in: 0...10)
print(a)
i += 1
}
}
First, note that I put these in a function. That's important. Putting them at the top level makes a a global in one case, and globals have special handling, including thread-safe initialization, which makes the "outside" case look more expensive and complicated than it would be in more normal usage. (It is very, very hard to correctly test micro-optimizations in such a way that you can draw general "this is faster" conclusions. There are so many factors.)
Second notice the print. We need to make sure to use a in a side-effecty way, or else the optimizer might remove it entirely. print is pretty good, even though it's quite complicated. You can also use the result to modify a global, but the compiler could definitely optimize that much more aggressively and might eliminate things we wanted to see. (You really really have to test this stuff on the actual case you care about.)
Now we can see what Swift is going to do with each of these using swiftc -O -emit-sil. That -O is critical. So many people try to do performance testing without turning on the optimizer, and those results are beyond meaningless.
So what's the SIL look like? (Swift Intermediate Language. This is the first big step towards turning your program into machine code. If two things generate the same SIL, they're going to generate the same machine code.)
The SIL is a little long (8000 lines), so I'm going to trim it a bit. My comments in <>. This is going to get a little tedious, because exploring this stuff is very nitpicky. If you want to skip it, the TL-DR is: there's no difference between these two pieces of code. Not "a small difference that won't matter." Literally (except for a hint to the debugger), no difference.
// runme()
sil hidden #$S4main5runmeyyF : $#convention(thin) () -> () {
bb0:
... <define a bunch of variables and function calls> ...
<compute the random number and put it in %29>
// %19 // user: %49
bb1(%19 : $Builtin.Int64): // Preds: bb5 bb0
%20 = alloc_stack $SystemRandomNumberGenerator // users: %23, %30, %21
store %2 to %20 : $*SystemRandomNumberGenerator // id: %21
br bb2 // id: %22
bb2: // Preds: bb3 bb1
%23 = apply %6<SystemRandomNumberGenerator>(%20, %5) : $#convention(method) <τ_0_0 where τ_0_0 : RandomNumberGenerator> (#inout τ_0_0, #thin UInt.Type) -> UInt // user: %24
%24 = struct_extract %23 : $UInt, #UInt._value // users: %28, %25
%25 = builtin "cmp_ult_Int64"(%24 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1 // user: %26
cond_br %25, bb3, bb4 // id: %26
bb3: // Preds: bb2
br bb2 // id: %27
bb4: // Preds: bb2
%28 = builtin "urem_Int64"(%24 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int64 // user: %29
%29 = struct $Int (%28 : $Builtin.Int64) // users: %42, %31
dealloc_stack %20 : $*SystemRandomNumberGenerator // id: %30
< *** Note that %29 is called "a" *** >
debug_value %29 : $Int, let, name "a" // id: %31
... < The print call. This is a lot more code than you think it is...> ...
< Add one to i and check for overflow >
%49 = builtin "sadd_with_overflow_Int64"(%19 : $Builtin.Int64, %8 : $Builtin.Int64, %13 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // users: %51, %50
%50 = tuple_extract %49 : $(Builtin.Int64, Builtin.Int1), 0 // users: %55, %53
%51 = tuple_extract %49 : $(Builtin.Int64, Builtin.Int1), 1 // user: %52
cond_fail %51 : $Builtin.Int1 // id: %52
< Loop if i < 100 >
%53 = builtin "cmp_slt_Int64"(%50 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 // user: %54
cond_br %53, bb5, bb6 // id: %54
bb5: // Preds: bb4
br bb1(%50 : $Builtin.Int64) // id: %55
bb6: // Preds: bb4
%56 = tuple () // user: %57
return %56 : $() // id: %57
} // end sil function '$S4main5runmeyyF'
The "outside" code is almost identical. What's different? Note where the *** in the code above marking the call to debug_value? That's missing in "outside" because a is defined as a function variable rather than a block variable.
Know what's missing in both of these? An alloc_stack call for "a". It's an integer; it can fit in a register. It's up to the lower level compiler whether it's stored in a register or the stack. The optimizer sees that "a" doesn't escape this region of the code, so it includes a hint for the debugger, but it doesn't actually bother to demand storage for it, not even on the stack. It can just take the return register of Random and move it to the parameter register for print. It's up to LLVM and its optimizer to decide all this.
The lesson from all this is that it literally doesn't matter for performance. In obscure cases where it might matter (such as when a is a global), version 1 would be more efficient, which I assume is the opposite of what you were expecting.
Swift handles this like most languages handle it. Local variables are declared on the stack, and popped off the stack when you exit the scope where they are defined. Pushing to and popping off of the stack is a very low-cost operation.
The LLVM compiler that Swift uses uses quite advanced code optimization, especially in release mode. In your trivial example the variables you're using the variables might well be optimized away anyway, since they aren't actually used for anything.
EDIT:
To summarize, there is no meaningful performance difference between the 2, and the first approach of putting the variable inside the loop is cleaner, as stated by rmaddy in his comment. Defining variables in the narrowest scope possible is a good policy. It shows your intent for the variable, and avoids unintended consequences.
Related
I am trying to implement an HTTP client in Rust using this as a starting point. I was sent to this link by the rust-lang.org site via one of their rust-by-example suggestions in their TcpStream page. I'm figuring out how to read from a TcpStream. I'm trying to follow this code:
fn handle_client(mut stream: TcpStream) {
// read 20 bytes at a time from stream echoing back to stream
loop {
let mut read = [0; 1028];
match stream.read(&mut read) {
Ok(n) => {
if n == 0 {
// connection was closed
break;
}
stream.write(&read[0..n]).unwrap();
}
Err(err) => {
panic!(err);
}
}
}
}
Where does the n variable come from? What exactly is it? The author says it reads 20 bytes at a time; where is this coming from?
I haven't really tried anything yet because I want to understand before I do.
I strongly encourage you to read the documentation for the tools you use. In this case, The match Control Flow Operator from The Rust Programming Language explains what you need to know.
From the Patterns that Bind to Values section:
In the match expression for this code, we add a variable called state to the pattern that matches values of the variant Coin::Quarter. When a Coin::Quarter matches, the state variable will bind to the value of that quarter’s state. Then we can use state in the code for that arm, like so:
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
If we were to call value_in_cents(Coin::Quarter(UsState::Alaska)), coin would be Coin::Quarter(UsState::Alaska). When we compare that value with each of the match arms, none of them match until we reach Coin::Quarter(state). At that point, the binding for state will be the value UsState::Alaska. We can then use that binding in the println! expression, thus getting the inner state value out of the Coin enum variant for Quarter.
There is an entire chapter about the pattern matching syntax available and where it can be used.
Figured it out, this is what's happening:
match stream.read(&mut read) {
This line is telling the software to pass stream.read(&mut read) to Ok(n) because stream.read returns the number of bytes read. I'm still not sure why they specify 20 bytes at a time as being read.
I'm using the prettier-vscode extension to format my js code, but flow annotations are formatted in a weird way with lots of extra space:
const handleResponse = async function < T > ( // <-- should be function<T>(
response,
url: string,
options: responseOptions = {}
): Promise < T | null > { // <-- should be Promise<T|null> {
or Promise<T | null> {
I've looked around in all the places I could think of to see what config I need to change to get this working, but I can't find anywhere that seems to affect the spacing in te above case.
There's also some weirdness going on with multi-line ternary statements, but I don't think that's related to flow:
const WORKORDERS_BASE_URL =
WORKORDERS_PORT === '80' ? // <-- I'd prefer if ? and : were on the next line
`http://${WORKORDERS_HOST}` : // <-- on same indentation level as above - I want one more
`http://${WORKORDERS_HOST}:${WORKORDERS_PORT}` // <-- same here, I want more indentation
The worst case of them all is this change, which happens when I format the document:
Promise<?T>
// becomes
Promise<<?T>
i.e. it actually breaks my code!
Where should I look for config that controls these things?
I have a bare bones struct.
struct Transaction {
var value: String = ""
var date: String = ""
var title: String = ""
}
In my project, Transaction is used like so...
var transaction:Transaction = Transaction()
//loops 3 times
repeat {
let parsed = stringAndType(from:myParser)//-> (string:String, type:UInt8)
switch parsed.type {
case 1:
print("1 -- \(parsed.string")
transaction.value = parsed.string
case 2:
print("2 -- \(parsed.string)")
transaction.date = parsed.string
case 4:
print("4 -- \(parsed.string)")
transaction.title = parsed.string
default: break
}
} while myParser.isOk
print("Returning transaction: \(transaction)")
return transaction
In this code, a structure is created. The parser feeds the data to the switch, which assigns the parsed string to the appropriate Transaction variable. When I run the following code, the output indicates that the assignments to transaction.date and transaction.value are not sticking.
Output:
2 -- 12/22/2015
1 -- -5.00
4 -- RECURRING PAYMENT BACKBLAZE
Returning transaction: Transaction(value: "", date: "", title: "RECURRING PAYMENT BACKBLAZE")
There is complex buffering behind the scenes in stringAndType(). Looking at this as a C programmer, I really want to think that function might be the problem. However, I was under the impression that Swift strings are structures, and are therefore copy on write, just like an integer or double. Hoping you can provide insight. Thank you for your time.
Update 02/15/17
The logic in this code is functioning as expected. I think the problem here is memory management. To help drive this point, I've...
Removed the print lines from my switch
Added didSet {} to each variable in Transaction
Like so...
struct Transaction {
var value: String = "" {
didSet {
print("The VALUE has changed from \(oldValue) to \(value)")
}
}
//this is repeated appropriately for the other two variables
}
The given output rules out any logical issues. Output:
The DATE has changed from to 12/22/2015
The VALUE has changed from to -5.00
The TITLE has changed from to RECURRING PAYMENT BACKBLAZE
Returning transaction: Transaction(value: "", date: "", title: "RECURRING PAYMENT BACKBLAZE")
stringAndType() does read from an unsafe buffer, but it copies the bytes to a Data structure, and returns a string initialized from the COPIED data. I thought this would insulate me from safety issues...perhaps theres an implementation detail to String I'm missing?
Credit to #unkgd, you were on the right track with your initial answer before you retracted it. There was a logical error between the while parser.isOk loop and the parent loop (omitted to keep the code short) that was wiping Transaction between value and title being set. There was no indication of this happening in the output. The loop posted above was not looping three times, rather, it was looping once, but that single loop was iterated three times by the parent. Therefore, only the most recent parsed value was stored in the structure, in this case, title. Again, full credit to #unkgd (if you repost your answer and I will mark it as correct). Thanks to everyone for their ideas.
When writing test code, I do a lot of this
if (!cond) {
t.Fatal("error message")
}
It's a bit tedious. So I'd like to achieve the following
CHECK(cond, "error message")
So I attempted this
func CHECK(t *testing.T, cond bool, fmt string, a ...interface{}) {
if !cond {
t.Fatal(fmt, a)
}
}
If it were a C macro it would've worked perfectly. But in Go, the line number where the failure is is wrong.
Is there a fix for this?
Sadly you can't do that.
A workaround would be to get the line / function yourself, something like the trace function from https://stackoverflow.com/a/25954534/145587.
You could possibly make use of runtime.Callers()+runtime.Caller(): the first one gives you the call stack while the second allows to extract the debug info about any arbitrary stack frame (obtained from that list).
Your CHECK() function is always one function call down the place the check should have happened at if it was a macro, so you can inspect the stack frame just above.
Update: the only functon which is really needed is runtime.Caller(). Here's your case, simplified:
package main
import (
"runtime"
"testing"
)
func CHECK(t *testing.T, cond bool) {
if !cond {
_, fname, lineno, ok := runtime.Caller(1)
if !ok {
fname, lineno = "<UNKNOWN>", -1
}
t.Fatalf("FAIL: %s:%d", fname, lineno)
}
}
func TestFoo(t *testing.T) {
CHECK(t, 12 == 13)
}
When saved as check_test.go and run via go test, it produces:
$ go test
--- FAIL: TestFoo (0.00 seconds)
check_test.go:14: FAIL: /home/kostix/devel/go/src/check/check_test.go:19
FAIL
exit status 1
FAIL check 0.001s
where line 19 is the line a call to CHECK() is located inside TestFoo().
While the above answer to use CHECK() function will work, I think that the actual answer is code readibility. Much of Go has been designed as a compromise to increase readibility among the community as a whole. See gofmt for example. Most people will agree that it's format is not best for every case. But having a convention agreed to by all is a huge plus for Go. The same answer is to your question. Go is for writing code for your peers, not for yourself. So don't think "I prefer this." Think "what will people reading my code understand."
Your original code should be like this, without parenthesis.
if !cond {
t.Fatal("error message")
}
This is idiomatic and every Go coder will recognize it instantly. That is the point.
I'm trying to parse a macro similar to this one:
annoying!({
hello({
// some stuff
});
})
Trying to do this with a procedural macro definition similar to the following, but I'm getting a behaviour I didn't expect and I'm not sure I'm doing something I'm not supposed to or I found a bug. In the following example, I'm trying to find the line where each block is,
for the first block (the one just inside annoying!) it reports the correct line, but for the inner block, when I try to print them it's always 1, no matter where the code is etc.
#![crate_type="dylib"]
#![feature(macro_rules, plugin_registrar)]
extern crate syntax;
extern crate rustc;
use macro_result::MacroResult;
use rustc::plugin::Registry;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::ext::quote::rt::ToTokens;
use syntax::codemap::Span;
use syntax::ast;
use syntax::parse::tts_to_parser;
mod macro_result;
#[plugin_registrar]
pub fn plugin_registrar(registry: &mut Registry) {
registry.register_macro("annoying", macro_annoying);
}
pub fn macro_annoying(cx: &mut ExtCtxt, _: Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
let mut parser = cx.new_parser_from_tts(tts);
let lo = cx.codemap().lookup_char_pos(parser.span.lo);
let hi = cx.codemap().lookup_char_pos(parser.span.hi);
println!("FIRST LO {}", lo.line); // real line for annoying! all cool
println!("FIRST HI {}", hi.line); // real line for annoying! all cool
let block_tokens = parser.parse_block().to_tokens(cx);
let mut block_parser = tts_to_parser(cx.parse_sess(), block_tokens, cx.cfg());
block_parser.bump(); // skip {
block_parser.parse_ident(); // hello
block_parser.bump(); // skip (
// block lines
let lo = cx.codemap().lookup_char_pos(block_parser.span.lo);
let hi = cx.codemap().lookup_char_pos(block_parser.span.hi);
println!("INNER LO {}", lo.line); // line 1? wtf?
println!("INNER HI {}", hi.line); // line 1? wtf?
MacroResult::new(vec![])
}
I think the problem might be the fact that I'm creating a second parser to parse the inner block, and that might be making the Span types inside it go crazy, but I'm not sure that's the problem or how to keep going from here. The reason I'm creating this second parser is so I can recursively parse what's inside each of the blocks, I might be doing something I'm not supposed to, in which case a better suggestion would be very welcome.
I believe this is #15962 (and #16472), to_tokens has a generally horrible implementation. Specifically, anything non-trivial uses ToSource, which just turns the code to a string, and then retokenises that (yes, it's not great at all!).
Until those issues are fixed, you should just handle the original tts directly as much as possible. You could approximate the right span using the .span of the parsed block (i.e. return value of parse_block), which will at least focus the user's attention on the right area.