just a short question regarding how to use TThreadList. Is it safe to use it with "with" statement as follows:
with FEngineList.DAQEngines.LockList do
begin
try
for Idx := 0 to Count - 1 do
Items[idx].Param1 := cos(2*pi*I/Count);
...
...
finally
FEngineList.DAQEngines.UnlockList;
end;
end;
or should I explicitly do it like here:
uEngines := FEngineList.DAQEngines.LockList;
try
with uEngines do
begin
for Idx := 0 to Count - 1 do
Items[idx].Param1 := cos(2*pi*I/Count);
...
...
end;
finally
FEngineList.DAQEngines.UnlockList;
end;
Thanks!
It's upon you which variant you choose. with only tells the compiler where to get members you write in your code. So yes, it is safe, as long as you're accessing members you wanted to. It doesn't affect the runtime.
I would prefer the first way, just without that begin..end block (if I'd be forced to use with), but it's just my personal preference and you are free to write it as you wish:
with FEngineList.DAQEngines.LockList do
try
...
finally
FEngineList.DAQEngines.UnlockList;
end;
Neither variant is to be recommended. If you had to choose between these two, the former is preferable since there is no real need for an extra local variable.
However, with is to be avoided. The problem is that is introduces potential for scope overlap. If the original scope and the object that is the subject of the with have members with the same name, then the with scope hides the outer scope. This catches you out when you add a new member to the subject of the with that happens to have the same name as a member of the outer scope. At best your program won't compile. At worst it compiles and you have a defect. Quite possibly a defect that you don't readily spot.
Code it like this:
uEngines := FEngineList.DAQEngines.LockList;
try
for Idx := 0 to uEngines.Count - 1 do
uEngines.[Idx].Param1 := Cos(2*pi*Idx/uEngines.Count);
....
end;
finally
FEngineList.DAQEngines.UnlockList;
end;
Related: Is Delphi "with" keyword a bad practice?
Related
I encountered a confusion , when i pass a variable x to variable y by reference then both x and y should now point to same location, but the output that i am getting is not same.
Full detail discussion is here: http://gateoverflow.in/94182/programming-output
I have tried my best to explain the stuff to user but i am still unable to convience him fully, maybe i am lacking some concept.
rough code sample:
var b : int;
procedure M (var a, int)
begin
a= a*a;
print(a);
end;
procedure N
begin
b= b+1;
M(b);
end;
begin
b=12;
N;
print(b);
end;
I assume that as in question it is given that variables are static , so the value of a b should not change from 13 , but the value of a should be 13*13=169 , but my reasoning is counter to what call by reference is about.
pascal code from unauthorized book, please throw some insights.
I had to review scoping terminology. I had myself confused between static and dynamic scoping. Static scoping is used in all modern programming languages. I conclude that both a and b should have a value of 169 at the respective print statements.
I got a great surprise when I noticed the following snippet not compiling:
aTime := time.Time{}
if defaultTime := time.Time{} ; aTime != defaultTime {}
The compiler returns:
type time.Time is not an expression
defaultTime := time.Time used as
value undefined: defaultTime
The intent here is to test the aTime variable if it's set to it's default value.
It also does not compile if I get the pointer of the struct (defaultTime := &time.Time{}).
However, it does compile if I init defaultTime outside of the if construct, or do the init using the new() builtin:
aTime := time.Time{}
if defaultTime := new(time.Time) ; aTime != *defaultTime {}
From what I've read everywhere, new(myStruct) it supposed to be completely equivalent to &myStruct{}.
As I interprate it, defaultValue := time.Time{} qualifies as a SimpleStmt (specifically an Assignment), as detailed in the If statement spec.
I've come up with no explanation for this behavior, despite my best googling efforts. Would be grateful if someone could make my head stop spinning.
The { is recognized as the beginning of a Block, terminating the parsing of the SimpleStmt. After committing to that decision, the compiler decides that, as a SimpleStmt, aTime := time.Time isn't valid because time.Time isn't a value that can be assigned. However, it's presumably too late for the parser to try another interpretation of the {.
The version with new works because it doesn't contain a { character, and so avoids confusing the parser in this way.
You can also use the literal format by wrapping it in parentheses, because a block can't legally begin in the middle of an expression, so this also works:
if defaultTime := (time.Time{}); aTime != defaultTime {
// ...
}
gofmt gives the helpful message "expected boolean expression, found simple statement (missing parentheses around composite literal?)", but oddly, the go compiler itself does not.
I don't think what I am going to suggest is necessarily a better solution. But for your use case, you can try this to be concise
if !aTime.IsZero() {
// ...
}
Ymmv
For some reason, the Maple code
testproc := proc()
LOCAL abc;
abc[1] := 123;
print(eval(parse(cat("abc[", 1, "]"))))
end proc
testproc();
produces
abc_1
whereas (same, but with abc now a GLOBAL variable)
testproc := proc()
GLOBAL abc;
abc[1] := 123;
print(eval(parse(cat("abc[", 1, "]"))))
end proc
produces (what I want)
123
What do I need to do so that I can evaluate a concatenated string involving a local variable? Many thanks for any help! :)
When you use parse, it operates as if the text was in its own file or entered at the top level. It doesn't have the context of lexically scoped variables.
You could do something like
eval(parse(cat("abc[",1,"]")),convert('abc',`global`)='abc');
If you want to handle multiple locals, use a set for the second argument to eval.
I assume you have some reason for going through the string form. For straight object manipulation, it isn't usually a good idea.
More Pascal woes.
Say I have 2 Units, MainUnit, and ExampleClass.
MainUnit:
Unit MainUnit;
interface
Uses ExampleClass;
function ReturnFive: Integer;
implementation
function ReturnFive: Integer;
begin
ReturnFive := 5;
end;
begin
end.
ExampleClass:
Unit ExampleClass;
{$mode objfpc}
interface
type
ClassThing = Class
SampleValue: Integer;
end;
implementation
begin
end.
Now, I'd like to only import MainUnit, but still be able to use ClassThing. MainUnit uses ExampleClass, but ClassThing isn't usable when you import MainUnit.
I don't really want to just use ExampleClass along with MainUnit, I'd prefer to keep it in one uses statement.
How do you do this?
put
type ClassThing = ExampleCLass.ClassThing;
in the interface of mainunit.
The principle also works for consts, but only "real" ones (not typed ones which are more initialized vars):
const myconst = unitname.myconst;
Nearly all my much used types are similar aliases, so that I can easily move around where they are defined without changing the uses clause in all the businesscode units
A code below is in a thread.
Tf1 := TFileStream.Create(LogsPath,fmOpenRead or fmShareDenyNone);
...
str:=TStringList.Create;
str.LoadFromStream(tf1);
...
SynEditLog.Lines.Assign(str); // I do this with Synchronize
There are 30 000 strings in a text document.
A form becomes frozen while assigning those strings to SynEdit.
If to load string by string it takes me 40 sec... If to use Assign - 8 sec.
How to prevent this form's state?
Thanks!!!
I don't think Application.ProcessMessages is going to help here at all, since all the work happens in the one call to Assign.
Does SynEditLog have BeginUpdate/EndUpdate methods? I'd use them and see how you go. For instance:
SynEditLog.BeginUpdate;
try
SynEditLog.Lines.Assign(str);
finally
SynEditLog.EndUpdate;
end;
In response to that not working
You'll need to break down the assignment of the string list to the Lines property. Something like this:
var
LIndex: integer;
begin
SynEditLog.BeginUpdate;
try
//added: set the capacity before adding all the strings.
SynEditLog.Lines.Capacity := str.Capacity;
for LIndex := 0 to str.Count - 1 do
begin
SynEditLog.Lines.Add(str[LIndex]);
if LIndex mod 100 = 0 then
Application.ProcessMessages;
end;
finally
SynEditLog.EndUpdate;
end;
end;
(note: code typed directly into browser, may not compile)
If this is too slow, try increasing the LIndex mod 100 = 0 to something larger, like 1000 or even 5000.
N#
The form is freezing because you're using the GUI thread to add 30,000 lines to your control, which naturally takes a while. During this time, the GUI can't update because you're using its thread, so it looks frozen.
One way around this would be to add a few lines (or just one) at a time, and, in between each add, update the GUI (by calling Application.ProcessMessages (thanks gordy)).