In the code: pbOut is a TPaintBox.
with pbOut.Canvas, Font do
begin
....
end;
The question is, i want to understand what does the comma in with.. do structure do? Is it the same as writing with pbOut.Canvas.Font do or not?
The comma is simply a separator for a list of things to 'scope to' using with.
As to your question, strictly speaking: it depends...
You might make the assumption that pbOut.Canvas always has a Font property (because you know TCanvas has a Font property). But nothing forces a Canvas variable to be of the TCanvas type, so you actually have to consider 2 possibilities.
In your case the first possibility explained below most likely applies, but it's important to be aware of the other.
As to your specific question:
Is it the same as writing with pbOut.Canvas.Font do or not?
It's almost the same, but not quite. That doesn't expose pbOut.Canvas, which the original code does.
Possibility 1
If Font is a member of pbOut.Canvas, then the statement is equivalent to:
with pbOut.Canvas do
begin
with pbOut.Canvas.Font do
begin
{ See notes underneath }
end;
end;
Here you are able to reference members of either pbOut.Canvas or pbOut.Canvas.Font directly; without fully qualifying the reference.
Any members in both pbOut.Canvas and pbOut.Canvas.Font that have have the same identifier would clash. The compiler will favour the inner with item. This means you would still have to fully qualify the pbOut.Canvas member to access it.
Possibility 2
On the other hand, if Font is not an accessible member of pbOut.Canvas, then the statement is equivalent to:
with pbOut.Canvas do
begin
with Font do
begin
{ See notes underneath }
end;
end;
Similar to the previous construct, you can access members of either pbOut.Canvas or Font directly; without fully qualifying the reference.
I must point out that the with statement is not really a useful construct.
It leads to confusing, difficult to read code because you always have to consider what an unqualified identifier really refers to.
There also a risk that adding/removing/renaming members in an existing object or record type might unexpectedly break existing code. Any code using with on instance of the modified type might unexpectedly scope differently.
The with list form in your question is even worse than single with because of the added trickery covered in my answer.
The with statement saves a small amount of code to more explicitly qualify certain identifiers; i.e. minimal "typing" savings, but at a great cost. So it is advised to not use with.
Look into documentation:
A with statement is a shorthand for referencing the fields of a record or the fields, properties, and methods of an object. The syntax of a with statement is:
with obj do statement
or:
with obj1, ..., objn do statement
where obj is an expression yielding a reference to a record, object instance, class instance, interface or class type (metaclass) instance, and statement is any simple or structured statement. Within the statement, you can refer to fields, properties, and methods of obj using their identifiers alone, that is, without qualifiers.
When multiple objects or records appear after with, the entire statement is treated like a series of nested with statements. Thus:
with obj1, obj2, ..., objn do statement
is equivalent to:
with obj1 do
with obj2 do
...
with objn do
// statement
In this case, each variable reference or method name in statement is interpreted, if possible, as a member of objn; otherwise it is interpreted, if possible, as a member of objn1; and so forth. The same rule applies to interpreting the objs themselves, so that, for instance, if objn is a member of both obj1 and obj2, it is interpreted as obj2.objn.
Since a with statement requires a variable or a field to operate upon, using it with properties can be tricky at times. A with statement expects variables it operates on to be available by reference.
Generally using with is a recipe for disaster, since by the look of it, it is difficult to know if a statement refers to one of the with blocks (and which one) or an outer scope.
To answer the question,
Is it the same as writing with pbOut.Canvas.Font do or not?
If you only want to access the Font properties it is the same, but not if you want to access other members of pbOut.Canvas.
For yours and others sake, do not use with statements at all.
Related
A quick screenshot with the point of interest:
There are 2 questions here.
This happens in a tight loop. The 12.8% code is this:
{
this with Side = side; PositionPrice = position'; StopLossPrice = sl'; TakeProfitPrice = tp'; Volume = this.Volume + this.Quantity * position'
}
This object is passed around a lot and has 23 fields so it's not tiny. It looks like immutability is great for stable code, but it's horrible for performance.
Since this recursive loop is run in parallel, I need to store it's context variables in an object.
I am looking for a general idea of what makes sense, not something specific to that code because I have a few tight loops with a bunch of math which I need to profile as well. I am sure I'll find the same pattern in several places.
The flaw here is that I store both the context for the calculations and its variables in a singe type that gets passed in the loop. As the variable fields get updated, the whole object has to be recreated.
What would make sense here (in general for this type of situations)?
make the fields that can change mutable. In this case, that means keeping the type as is (23 fields) and make some fields mutable (only 5 fields get regularly changed)
move the mutable fields to their own type to have a general context object and one holding all the variables. In this case, that means having a context with (23 - 5 fields) and a separate 5 fields type
make the mutable fields variables and move them out of the type. In this case, these 5 fields would be passed as variables in the recursive loop?
and for the second question:
I have no idea what the 10.0% line with get_Tag is. I have nothing called 'Tag' in the code, so I assume that's a dotnet internal thing.
I have a type called Side and there is a field with the same name used in the loop, but what is the 'Tag' part?
What I would suggest is not to modify your existing immutable type at all. Instead, create a new type with mutable fields that is only used within your tight loop. If the type leaves that loop, convert it back to your immutable type (assuming you don't need a copy to go through the rest of your program with every iteration).
get_Tag in this case is likely the auto-generated get-only property on a discriminated union, it's just how the F# compiler represents this sort of type in CLR. The property can most easily be seen when looking at F# code from C#, here's a great page on F# decompiled:
https://fsharpforfunandprofit.com/posts/fsharp-decompiled/#unions
For the performance issues I can only offer some suggestions:
If you can constrain the context object to your code only, then try making a mutable version and see which effect it has.
You mention that the context object is quite large, is it possible to split it up?
In the documentation under case statements, it says:
Each value represented by a caseList must be unique in the case
statement;
And the example shown,
case I of
1..5: Caption := 'Low';
6..9: Caption := 'High';
0, 10..99: Caption := 'Out of range';
else
Caption := ;
end
is equivalent to the nested conditional:
if I in [1..5] then
Caption := 'Low';
else if I in [6..10] then
Caption := 'High';
else if (I = 0) or (I in [10..99]) then
Caption := 'Out of range'
else
Caption := ;
So the first quote suggests it is handled like a set (read the comments here at least one person is with me on this).
Now I know the part
where selectorExpression is any expression of an ordinal type smaller
than 32 bits
contradicts with the properties of sets as it is mentioned her under sets:
The base type can have no more than 256 possible values, and their
ordinalities must fall between 0 and 255
What is really bugging me is that why it is a necessity to have a unique values in the caseList. If it is equivalent to the if statement, the second value would be just not tested because the compiler already found a prior match?
The documentation takes a specific case statement which is equivalent to a specific if statement.
In general, any case statement can be rewritten as an if statement using the same approach. However, the inverse is not true.
The documentation uses an equivalent if statement to explain the logical behaviour (or semantics) of the case statement. It's not a representation of what the compiler does internally.
How does the compiler handle case statement?
First note there are 2 aspects to this question.
Semantically the compiler must handle the case statement as indicated in the documentation. This includes:
Ensuring the values of each caseList entry can be evaluated at compile-time.
Ensuring the caseList entries are unique.
Whichever caseList entry matches, the corresponding caseList-statement is called.
If no caseList entries match, the else statements are called.
However, the compiler is entitled to optimise the implementation as it sees fit provided the optimised byte/machine code is logically equivalent.
Johan's answer describes common optimisations: jump-lists and reordering.
These are much easier to apply given the strict semantics.
What is really bugging me is that why it is a necessity to have a unique values in the caseList.
The uniqueness is required to remove ambiguity. Which caseList-statement should be used if more than one matches?
It could call the first matching caseList-statement and ignore the rest. (SQL Server CASE statement behaves like this.) Also see [1] below.
It could call all of them. (If I remember correctly the MANTIS programming language uses this semantic for its version of a case statement.)
It could report an error requiring the programmer to disambiguate the caseList. (Simply put, this is what Delphi's specification requires. Many other languages use the same approach. Quibbling about it is unproductive especially since this choice is unlikely to be much of a hindrance.)
If it is equivalent to the if statement the second value would be just not tested because the compiler already found a prior match.
[1] I'd like to point out that this can make code much more difficult to read. This behaviour is "ok" when using magic literals, but when using const identifiers it becomes dangerous. If 2 different consts have the same value, it won't be immediately apparent that the latter caseList-statement where the caseList also matches won't be called. Also case statements would be subject to behaviour change due to a simple caseList re-ordering.
const
NEW_CUSTOMER = 0;
EDIT_CUSTOMER = 1;
...
CANCEL_OPERATION = 0;
case UserAction of
NEW_CUSTOMER : ...;
EDIT_CUSTOMER : ...;
...
CANCEL_OPERATION : ...; { Compiler error is very helpful. }
end;
Contradicts with the properties of sets
There's no contradiction. The fact that each caseList value must be unique does not in any way imply it must be "handled like a set". That's your incorrect assumption. Other's making the same assumption are likewise incorrect.
How the uniqueness constraint is checked, is up to the compiler. We can only speculate. But I'd guess the most efficient would be to maintain an ordered list of ranges. Work through each of the caseList of values and ranges, find its position in the above list. If it overlaps, then report an error, otherwise add it to the list.
case statement
The compiler prefers to transform the case statement to a jump table.
In order to make this possible duplicate case labels are not allowed.
Furthermore the compiler does not have to test the case statements in the order you've declared them. For optimization reasons it will reorder these elements as it sees fit; so even if it does not use a jump table, it still cannot allow duplicate case labels.
It is for these same reason (and to keep programmers mentally sane) that the case statement does not allow fall-throughs.
if statement
A (series of) if statements are processed in the order they are declared.
The compiler will test them one by one (and jump out when appropriate).
If the if-statement does not contain duplicates the code will perform the same as an equivalent case statement, but the generated code will most likely be different.
If statements are never converted into jump tables.
about sets
The reason sets are limited to 256 elements is that every element in a set takes up one bit of space.
256 bits = 32 bytes.
Allowing more than 256 elements in a set would grow the representation in memory too much, hampering performance.
The case statement does not use sets, it merely uses set logic in its semantics.
I came across something in the Delphi language that I hadn't noticed before. Consider a simple record and a pointer to that record:
TRecord = record
value : double;
end;
PTRecord = ^TRecord;
Now declare a variable of type PTRecord:
var x : PTRecord;
and create some space:
x := new (PTRecord);
I noticed that I can access the value field using both the '.' notation and the '^.' notation. Thus the following two lines appear to be operationally equivalent, the compiler doesn't complain and runtime works fine:
x.value := 4.5;
x^.value := 2.3;
I would have thought that '^.' is the correct and only way to access value? My question is, is it ok to use the simpler dot notation or will I run into trouble if I don't use the pointer indirection '^.'? Perhaps this is well known behavior but it's the first time I've come across it.
It is perfectly sound and safe to omit the caret. Of course, logic demands the caret, but since the expression x.value doesn't have a meaningful intepretation in its own, the compiler will assume you actually mean x^.value. This feature is a part of the so-called 'extended syntax'. You can read about this at the documentation.
When Extended syntax is in effect (the default), you can omit the caret when referencing pointers.
Delphi has supported that syntax for close to two decades. When you use the . operator, the compiler will apply the ^ operator implicitly. Both styles are correct. There is no chance for your program doing the wrong thing since there is no case where presence or absence of the ^ will affect the interpretation of the subsequent . operator.
Although this behavior is controlled by the "extended syntax" option, nobody ever disables that option. You can safely rely on it being set in all contexts. It also controls availability of the implicit Result variable, and the way character pointers are compatible with array syntax.
This is called implicit pointer dereferencing for the structured types and inherited from the Delphi 1. This language extension aims to make accessing members of classes (classes are structured types and also instances are implicit pointers) by the means of membership operator (.) only, avoiding requirement for explicit dereference operator (^).
You can safely rely on the presence of this extension in the all Delphi compilers. For more flexibility you can test for the presence of this extension by using $IFOPT X+ conditional directive.
I have types in distincts units with the same name and I have the unit name in a string. I need to access the specific type of this unit. How do I do that?
Example:
unit Unit1
type
TFooType = (
bar1,
bar2
);
then, I have another unit
unit Unit2
type
TFooType = (
foo1,
foo2,
foo3
);
And, somewhere in my code I have the a string variable "UnitName" with the value 'Unit1' within it and I want to access the Unit1's "TFooType" type by the variable.
I'm using Delphi 2007
Sorry for my bad english.
Thanks in advance.
You can't choose which units to include at run time. Units are a compile-time concept.
Furthermore, your two types, despite having the same base name, are completely distinct types. Elsewhere in your code, you cannot have a variable of type TFooType and arbitrarily decide whether to assign it values from both of those units. The variable can only hold values from one type.
You're going to have to think of some other way of accomplishing your real task. I invite you to post a new question describing what your real task is.
#Hrukai, Just like with lego, there's a lot you can do, but somethings just weren't designed to be used that way.
Sounds to me like your end goal is to access the type, and your starting point is a variable name. Had you implemented your variables as classes (OOP), you could simplly do Obj.ClassName to find its type... but also, had you chosen classes for your implementation, I predict this need (to access the type from the variable) would have never arisen in the first place.
Resist the urge to create a new pattern, and instead exploit the power of classes.
http://www.delphibasics.co.uk/Article.asp?Name=OOExample
The best you could do would be something like if name='Unit1' then T := Unit1.TFoo etc. But what can you do with T anyway? Since the enumerated types from the different units are different, it's hard to imagine being able to anything with T. In fact how would you even define T? The only thing I could imagine would be possible would be to return the type info but I'm letting my imagination run wild now!
In the process of transforming a given efficient pointer-based hash map implementation into a generic hash map implementation, I stumbled across the following problem:
I have a class representing a hash node (the hash map implementation uses a binary tree)
THashNode <KEY_TYPE, VALUE_TYPE> = class
public
Key : KEY_TYPE;
Value : VALUE_TYPE;
Left : THashNode <KEY_TYPE, VALUE_TYPE>;
Right : THashNode <KEY_TYPE, VALUE_TYPE>;
end;
In addition to that there is a function that should return a pointer to a hash node. I wanted to write
PHashNode = ^THashNode <KEY_TYPE, VALUE_TYPE>
but that doesn't compile (';' expected but '<' found).
How can I have a pointer to a generic type?
And adressed to Barry Kelly: if you read this: yes, this is based on your hash map implementation. You haven't written such a generic version of your implementation yourself, have you? That would save me some time :)
Sorry, Smasher. Pointers to open generic types are not supported because generic pointer types are not supported, although it is possible (compiler bug) to create them in certain circumstances (particularly pointers to nested types inside a generic type); this "feature" can't be removed in an update in case we break someone's code. The limitation on generic pointer types ought to be removed in the future, but I can't make promises when.
If the type in question is the one in JclStrHashMap I wrote (or the ancient HashList unit), well, the easiest way to reproduce it would be to change the node type to be a class and pass around any double-pointers as Pointer with appropriate casting. However, if I were writing that unit again today, I would not implement buckets as binary trees. I got the opportunity to write the dictionary in the Generics.Collections unit, though with all the other Delphi compiler work time was too tight before shipping for solid QA, and generic feature support itself was in flux until fairly late.
I would prefer to implement the hash map buckets as one of double-hashing, per-bucket dynamic arrays or linked lists of cells from a contiguous array, whichever came out best from tests using representative data. The logic is that cache miss cost of following links in tree/list ought to dominate any difference in bucket search between tree and list with a good hash function. The current dictionary is implemented as straight linear probing primarily because it was relatively easy to implement and worked with the available set of primitive generic operations.
That said, the binary tree buckets should have been an effective hedge against poor hash functions; if they were balanced binary trees (=> even more modification cost), they would be O(1) on average and O(log n) worst case performance.
To actually answer your question, you can't make a pointer to a generic type, because "generic types" don't exist. You have to make a pointer to a specific type, with the type parameters filled in.
Unfortunately, the compiler doesn't like finding angle brackets after a ^. But it will accept the following:
TGeneric<T> = record
value: T;
end;
TSpecific = TGeneric<string>;
PGeneric = ^TSpecific;
But "PGeneric = ^TGeneric<string>;" gives a compiler error. Sounds like a glitch to me. I'd report that over at QC if I was you.
Why are you trying to make a pointer to an object, anyway? Delphi objects are a reference type, so they're pointers already. You can just cast your object reference to Pointer and you're good.
If Delphi supported generic pointer types at all, it would have to look like this:
type
PHashNode<K, V> = ^THashNode<K, V>;
That is, mention the generic parameters on the left side where you declare the name of the type, and then use those parameters in constructing the type on the right.
However, Delphi does not support that. See QC 66584.
On the other hand, I'd also question the necessity of having a pointer to a class type at all. Generic or not. they are needed only very rarely.
There's a generic hash map called TDictionary in the Generics.Collections unit. Unfortunately, it's badly broken at the moment, but it's apparently going to be fixed in update #3, which is due out within a matter of days, according to Nick Hodges.