Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connections
Warning: mysqli::query(): Couldn't fetch mysqli in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\index.php on line 66
Article <vbgb5q$1ruv8$1@paganini.bofh.team>
Deutsch   English   Français   Italiano  
<vbgb5q$1ruv8$1@paganini.bofh.team>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!npeer.as286.net!dummy01.as286.net!peer02.ams1!peer.ams1.xlned.com!news.xlned.com!peer03.ams4!peer.am4.highwinds-media.com!news.highwinds-media.com!nntp.comgw.net!newsfeed.bofh.team!paganini.bofh.team!not-for-mail
From: Waldek Hebisch <antispam@fricas.org>
Newsgroups: comp.lang.c
Subject: Re: Top 10 most common hard skills listed on resumes...
Date: Sat, 7 Sep 2024 01:44:28 -0000 (UTC)
Organization: To protect and to server
Message-ID: <vbgb5q$1ruv8$1@paganini.bofh.team>
References: <vab101$3er$1@reader1.panix.com>   <vanq4h$3iieb$1@dont-email.me> <875xrkxlgo.fsf@bsb.me.uk> <vapitn$3u1ub$1@dont-email.me> <87o75bwlp8.fsf@bsb.me.uk> <vaps06$3vg8l$1@dont-email.me> <871q27weeh.fsf@bsb.me.uk> <20240829083200.195@kylheku.com> <87v7zjuyd8.fsf@bsb.me.uk> <20240829084851.962@kylheku.com> <87mskvuxe9.fsf@bsb.me.uk> <vaq9tu$1te8$1@dont-email.me> <vbci8r$1c9e8$1@paganini.bofh.team> <vbcs65$eabn$1@dont-email.me> <vbekut$1kd24$1@paganini.bofh.team> <vbepcb$q6p2$1@dont-email.me>
Injection-Date: Sat, 7 Sep 2024 01:44:28 -0000 (UTC)
Injection-Info: paganini.bofh.team; logging-data="1965032"; posting-host="WwiNTD3IIceGeoS5hCc4+A.user.paganini.bofh.team"; mail-complaints-to="usenet@bofh.team"; posting-account="9dIQLXBM7WM9KzA+yjdR4A";
User-Agent: tin/2.6.2-20221225 ("Pittyvaich") (Linux/6.1.0-9-amd64 (x86_64))
X-Notice: Filtered by postfilter v. 0.9.3
X-Received-Bytes: 12960
Bytes: 13085
Lines: 281

Bart <bc@freeuk.com> wrote:
> On 06/09/2024 11:19, Waldek Hebisch wrote:
>> Bart <bc@freeuk.com> wrote:
> 
>>> If you've followed the subthread then you will know that nobody disputes
>>> that assignment reads from side of '=' and writes to the other.
>> 
>> I dispute this and I think that to same degree several other folks too.
>> Assgmenet _does not read_, it "only" writes.  Assigment get two
>> parameters which are treated in different way.  Imagine that you
>> are programming in a language like C, but are forbidden to use
>> assignment operator.  But fortunately you have C "function"
>> 'assign' with prototype:
>> 
>> void assign(int * p, int v);
>> 
>> Instead of writing
>> 
>>      A = B
>> 
>> you need to write
>> 
>>      assign(&A, B)
> 
>> Of course, in real life nobody is going to force you to anything,
>> but except for fact that in C assignment has value the 'assign'
>> function is doing the same thing as '=' operator.  And you can
>> see that it is asymetric: first agrument is an addres and right
>> is a value.
> 
> If you have to use a function, yes. Because you've introduced an 
> artificial split in Where and When those dereferences are done.

Well, this is natural if you want simple semantics.  As result of
parsing you ge a parse tree (it does not matter if parse tree
exists as a real data structure or is just a conceptual thing).
To get meaning of an expression you get meanings of arguments,
which conceptually is simple recursion (pragmaticaly compiler
may work in bottom-up way) and then you get meaning of whole
expression by applying operator at the top to meanings of the
subtrees.  Point is that once you got meaning of a subtree
it does not change, so you can throw out source subtree.
In terms of code generation you can immediately generate
code and there is no need to change it after it is generated
(no need to turn read opcodes into writes).

> With A=B they can be done at about the same time and the same place.
> 
> With ASSIGN(), the B dereference is done at the call-site; the A 
> deference is done inside ASSIGN(), so you are obliged to pass an 
> explicit reference to A. While B has already been dereferenced and you 
> have its value to pass.
> 
> (You can balance it out by by requiring ASSIGN(&A, &B)!)

This would not work in general, as I wrote it, the following are
valid:

assign(&a, 42)
assign(&a, a + 1)

but the second argument has no address, so your variant would not
work.

As I wrote, implementing this leads to very simple compiler, that
is why Forth uses that way.  In optimizing compiler you want to
allocate variables into registers, and for this you need to get
rid of addresses (when you use variable address variable can not
be in register (some machines have/had addressable registers,
but even if you can address registers this usually leads to
slow code)).  So probably using read/write variable accesses
leads to overall simpler compiler (with more complex front end,
but simpler optimizer).  I have read that DEC had highly optimizing
Bliss compiler, I am not sure it this was due to Bliss features
or despite Bliss features.

>>> If A is in memory then it could be the same on 2-address architectures:
>>>
>>>      mov [A], [A]
>>>
>>> but more typically it needs two instructions (here using RTL):
>>>
>>>     mov R, [A]
>>>     mov [A], R
>>>
>>> Here, [A] appears in both instructions, it means the same thing, and
>>> refers to the same location. Only the position (left vs. right operand,
>>> exactly the same as in A = A) tells you if it's reading or writing.
>>   
>> You somewhat miss fact that "A = B" has 3 parts, that is "A", "=", and "B".
>> The second 'mov' instruction came from "=", the first 'mov' is extra.
>> So instructions look symmetric, but clearly assigment part is asumetric.
> 
> Here is A:=B from my HLLs in one of my ILs (intermediate language):
> 
>     load  B
>     store A
> 
> That was stack-based; here it is in 3-address-code IL:
> 
>     a := b         # more formally, 'move a, b'
> 
> This is it in dynamic byte-code:
> 
>     push B
>     pop  A
> 
> In every case, both A and B operands have the same rank and the same 
> levels of indirection.

You can use stack machines to get reasonably simple definition of
semantics.  But still slightly more complex than what I outlined
above.  And code for stack machines is unpleasent to optimize.
In a compiler for a language where official semantics is stack
based the first things that compiler does is to track few items
on top of the stack and match them to sequences like

push a
push b
call op

Once sequence is matched it is replaced by corresonding operation
on variables.  If this matching works well you get conventional
(non-stack) intermediate representaion and reasonably good code.
If matching fails, the resulting object code wastes time on stack
operations.

Of course, if you don not minds slowdowns due to stack use, then
stack machine leads to very simple implemantaion.  Best Forth compilers
have sophisticated code to track stack use and replace it by
use of registers.  Other Forth compilers just accept slowness.

>>> There is a Load on one operand and a balancing Store on the other. Two
>>> loads or two stores would not make sense here.
>> 
>> Again: only store comes from assignment.  This is clearly visible
>> if instead of misleading "A = A" you take "A = B" and replace
>> 'B' by various things.  Assigment part (store instruction) stays
>> the same, compution of value changes.  In
>> 
>> A = c  + d
> 
> This has been covered. The syntactical symmetry is that whatever you 
> have on the LHS, you can write the same thing on the RHS:
> 
>     A[i+1].m = A[i+1].m
> 
> Obviously, you can have RHS terms that cannot appear on the left, like 
> '42', but that's usually due to separate constraints of the language.

Well, logically you can not change value of a number, so you can
not assign to a number, that is very fundamental.  You could
try to define

x + 1 = y

as solving equation for x, that quickly runs into trouble due to
equations which are no solutions or multiple solutions.  And solving
frequently is a complex process, not suitable as basic operation.
OK, if you trurly insist on symmetry, than Prolog unification
is symmetric, here information can flow in both directions.
But unification is quite different than assigment.

>> you get two load (for c and d) and then addition.  To put it
>> differently, you have
>> 
>> compute value of B
>> compute address of A
>> store
> 
> Why don't you need to compute the address of B?

Well, B may have no address.  In case when B is variable computing
its address is part of computation of its value.  In general,
computing value of B need computing addresses of all variables
contained in B.

> Why don't you need to 
> load the value of B?

"compute value" means putting result in place which is available
to subsequent operations, so logically no extra load is needed.
And for variables "compute value" includes loading them.

========== REMAINDER OF ARTICLE TRUNCATED ==========