|
If you look closely, you will find that this is the right spelling in this case: BLADES
The language is JavaScript. that of Mordor, which I will not utter here
This is Javascript. If you put big wheels and a racing stripe on a golf cart, it's still a f***ing golf cart.
"I don't know, extraterrestrial?"
"You mean like from space?"
"No, from Canada."
If software development were a circus, we would all be the clowns.
|
|
|
|
|
Quite right too. I was wondering what on earth he was on about.
Regards,
Rob Philpott.
|
|
|
|
|
Bear with him. He was just a bit tyred!
Anything that is unrelated to elephants is irrelephant Anonymous
- The problem with quotes on the internet is that you can never tell if they're genuine Winston Churchill, 1944
- I'd just like a chance to prove that money can't make me happy. Me, all the time
|
|
|
|
|
Right now I feel very, very, very...
The language is JavaScript. that of Mordor, which I will not utter here
This is Javascript. If you put big wheels and a racing stripe on a golf cart, it's still a f***ing golf cart.
"I don't know, extraterrestrial?"
"You mean like from space?"
"No, from Canada."
If software development were a circus, we would all be the clowns.
|
|
|
|
|
I still miss one construct from a proprietary systems programming language I was using 3o years ago:
Frequently, executing a loop, and exiting from it, has two different outcomes. E.g. you search a list or a table, and find what you were searching for. Or you do not find what you were searching for. The two cases often require distinctly different post processing. In C class languages, one way of handling this is to declare a bool outside the loop, initialize it, possibly modifying it in the loop before exiting, testing it after the loop and to either this or that.
This bool variable really isn't a variable; it is flow control. So it isn't good. And, the termination handling is syntactically detached from the loop it applies to; that isn't good either. Finally: Due to this detaching, the termination handling being outside the loop, it does not have access to the inner working of the loop, such as those values causing the loop exit.
With this language constuct I am missing, you can specify two alternate loop 'tails': One if the loop came to an end ('exitfor'), another if the loop was left prematurely due to some specific condition not being satisfied ('exitwhile'). Both tails are syntactically part of the loop, with access to loop local variables. No flow control variables need to be declared, set or tested. An example: Search a list for a key (here: 'refkey'). If the key is found, increment 'refcount'. If not, insert a new element in the list and set 'refcount' to 1:
for (Listelt elt in mylist) {
.
. until (elt.key == refkey);
.
. exitfor
. mylist.insert(new Listelt(refkey,1));
. exituntil
. elt.refcount++;
}
The corresponding plain C# code, without exit clauses, would look like
. Listelt eltfound = null;
. for (Listelt elt in mylist) {
.
. if (elt.key == refkey) {
. eltfound = elt;
. break;
. }
.
. }
. if (eltfound != null) {
. elt.refcount++;
. }
. else {
. mylist.insert(new Listelt(refkey,1));
. }
... which I think is far less explit / readable, more error prone, and introduces variables ('eltfound') which really are relevant to the loop only, but defined in a much wider scope. Besides, the tail if/else is syntactically outside the loop, and has not access to relevant data within the loop.
I am not a particular strong fan of conceptually superfluous bracketing constructs - C class languages have some silly {}-requremnents! In the language where I picked this up, there are less of those, and 'exitfor' serves as a delimiter, allowing any number of statement down to the either 'exitwhile' or the loop end. Similarly, the 'exitwhile' block may have multiple statements. In C class languages, {} would probably be needed.
In the original design, a loop might have several 'until' tests; they would all end up in the same 'exituntil'. I would like a way to optionally attach a label to an 'until' test and one or more labels to the 'exituntil' block (which could then have several alternatives differently labeled) - that would make the mechanism even more useful. (Strictly speaking, the original design used 'while' tests rather than 'until', 'exitwhile' rather than 'exituntil'. Since C# already has a 'while' with different semantics, reversing the test and calling it 'until' fits the C class languages much better.)
I have tried to create '#define' to emulate this by generating 'goto' to generated labels, but never really succeeded. Besides, the compiler doesn't know that the 'exit' part is done after termination, so modifing the list inside the loop might be prohibited (in C#). If the exit parts were part of the language, the compiler would know that modifying the list is OK - there will be no more iterations.
Would this extension have any disavantages, except for the obvious one of introducing new reserved words? (I don't think 'exitfor' and 'exituntil' are very common as variable or function names, though!)
|
|
|
|
|
Will your C# code even compile? I might be missing something here. elt will not be accessible outside the foreach .
I think I kind of understand what you are talking about. Do Any or Where extension methods help in these situations?
"It is easy to decipher extraterrestrial signals after deciphering Javascript and VB6 themselves.", ISanti[ ^]
|
|
|
|
|
That should of course be: eltfound.refcount++;
rather than: elt.refcount++;
As I wrote: The traditional way of doing it is error prone!
|
|
|
|
|
A better solution would be a generic "not completed" detector:
for (...)
{
}
onbreak
{
} Which could work with for, foreach, while, etc.
But to be honest, I find it pretty natural to either use a bool or put the loop code in a separate method - which has the advantage of reducing the code size in the original one as well.
I can't see that this is really needed myself, but that's just my opinion.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
That 'onbreak' handles the 'exituntil' part.
It does not handle the 'exitfor' part - the code which is to be executed if you come to the end of the loop.
Besides, the way you define it: The block which contains the iterated code, the top {} pair, is closed and dead when you come to the onbreak {} part. So whichever variables were used in the loop - such as those causing the break condition, are inaccessible to the onbreak {}. I certainly hope that you are not going to suggest that local variables within the for {} block shall be accessible to the onbreak {} block!
Putting the loop code in a separate method helps nothing to handle alternate exit paths without having to set boolean flags. If you meant to include the alternate exit handlers in the method, what is the point of the method? If not: How would you indicate the required exit handling upon return to the caller of that method? How would the exit handlers be able to access the values causing that specific exit action, values local to the loop (function)?
You have another parsing problem in your proposal: The for loop is syntactically completed at the closing }. What follows it, could be any statement. You introduce an onbreak statement, not an onbreak clause of the for statement. The semantics of the for loop is modified by an adjacent statement (i.e. the onbreak) - that is sort of messy.
Obviously, I would like to have the exit clauses available in both for loops, foreach looops etc - the language providing exit clauses has a generalized 'for' control construct that covers both 'for' and 'foreach'). It also allows several exit tests (like the 'until') for while loops, similar to several 'if (cond) break;' - but since the main point is to provide different termination handling under different conditions, the mechanism would be most useful if you could provide arbirarily many 'exituntil' type clauses. I ceratainly would welcome that!
When I first was offered these alternate exit paths, it took me a while to see its real usefulness. But once you have learned to use it, and then move over to a language without it, you all the time tell yourself 'This would just have been so much more elegant if alternate exits were provided!'.
|
|
|
|
|
Member 7989122 wrote: C class languages have some silly {}-requremnents!
They don't.
If anything C has too few by allowing unbracketed one-liners for loops and conditions.
if (Whatever)
DoSomething();
is both a little untidy and slightly dangerous as there's no really visible connection between action and condition. Stuff gets moved or removed and things start to go wrong.
For my money, the compiler should insist on:
if (Whatever)
{
DoSomething();
}
|
|
|
|
|
Or better:
if (Whatever)
{
DoSomething();
}
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
That's just bad indentation!
|
|
|
|
|
I prefer that the { comes together with the indentation; the indentation starts with the {. In your layout, it doesn't: The indentation starts before the {.
Then, I also like the indentation to end with the }. If the } is undented, the undentation comes before the }, which is, in my eyes, similarly inconsistent.
Finally: When you read an if, then the condition, then ... What??? something is missing here! I don't like that, either. If the conditional statement doesn't fit on the same line, it is not empty but contains an announcer: Conditional statement(s) follow below, indented.
So my preferred style is
if (whatever) {
DoSomething();
}
|
|
|
|
|
Let the Holy Wars resume!
If you have an important point to make, don't try to be subtle or clever. Use a pile driver. Hit the point once. Then come back and hit it again. Then hit it a third time - a tremendous whack.
--Winston Churchill
|
|
|
|
|
In Pascal, a statement is a block. Anywhere a block is required, a statement will do, because it is a block.
In C, a statement is not a block. Several productions require a block (e.g. a catch() {}), so you have to create a block out of a single statement by enclosing it in {}.
You may argue: Well, there's the explanation for those {} requirements - they are there to create a block! They are not superfluous.
Yes, if you without any question accept the way C grammar was defined, of course you find it obvious that the {} should be there. So the problem is not in the {} themselves, but in that a statement was not defined as a block, the way it in Pascal. But the end result is the same: In C, you several places need to add {} around a single statement, where Pascal does not require any bracketing constructs.
This holds for several other languages as well - I refer to Pascal because it is the most well known of those.
That bracketing constructs in Pascal are more voluminous (BEGIN - END) than {} is just a small detail related to the parsing of tokens; it is irrelevant to the syntax productions.
Most non-C algorithmic languages don't even need any () bracketing of the condition in 'if' and loop constructs - yet they allow for just as general logical expressions as C does.
The try-catch is another silly bracketing mechanism. Pascal's origins are older than the exception concept, but in other language like CHILL, any block (including a statement, which is a block) is an implict try-block: Between the block and the terminating semicolon, an ON clause may be put (ON corresponds to 'catch'). You need no pre-announcement like 'try', you need no braces just to identify what is being tried - the handler implicitly applies to the block to which it is attached.
The C language was not created by people who were experts on language design, but by programmers who did it as a left hand job inbetween lots of other work. C is that way because... well... that's just how it was done, take it or leave it... On the other hand, Pascal was Designed by a qualified Language Designer, according to a plan and with a well defined goal.
That being said: There are several cases of language designs so academic and theoretically perfect, and without any pragmatic adaptations whatsoever, that they are almost impossible to work with. It is certainly possible to overdo design! You need a teaspoonfull of pragmatism in any design. But C is not a teaspoonfull of pragmatism in a design, it is huge showels of pragmatism without any design at all. That pragmatism overload does not make it useful, it makes a mess. Well, since K&R C, the language has been tightened up in several aspects. C# is the better of the C crowd, and can be tolerated. But it never got rid of those "superfluous" {}, the parenthesising of logical expressions and that super-ugly exception syntax, which is a pity.
|
|
|
|
|
My gut reaction is that I don't like it. It doesn't seem to add any significant benefit, and your proposed syntax just doesn't feel like C# to me.
But, if you want to suggest it to, and discuss it with, the language designers, open an issue on the Roslyn GitHub repo[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Maybe the tokens I used do not have a 'C# feeling' - the C lanugage class is certainly not very fond of keywords - it should rather be some punctuation. So I understand your reaction.
But that is not the main point. The main point is to provide a first class flow control mechanism that allows alternate exit paths from a loop. That I think (well, I know, from practical experience!) is a definite and significant benefit.
So, I would certainly accept other, more "C feeling" tokens, if only the semantics is in place.
|
|
|
|
|
Maybe that could've been an article, eh?
|
|
|
|
|
I am not really into writing articles... (Well, 20-30 years ago when I was young and ambitions, I did write papers and articles, but my ambitions have dwindled away )
If you are serious, not joking: Are you thinking of a CodeProject article, or something else?
Are ideas about language extensions a suitable topic for CP artibles?
|
|
|
|
|
It sounds like you are reinventing the n+1/2 ('n' and a half) times loop. I included that as a construct in a FORTRAN pre-processor in the late 1970s when it looked like
LOOP
statements
EXITIF condition
statements
EXITIF condition
statements
ENDLOOP
with this construct you can not only implement n+1/2 times loops but also implement WHILE loops, e.g.
LOOP
EXITIF NOT condition
statements
ENDLOOP
and UNTIL loops e.g.
LOOP
statements
EXITIF condition
ENDLOOP and FOR loops e.g.
cv = initialvalue
LOOP
EXITIF cv > endvalue
statements
cv = cv + increment
ENDLOOP
For your classic find value in an array search:
found = noofitemsinarray
LOOP
found = found - 1
EXITIF found < 0
EXITIF array(found) = itemtofind
ENDLOOP
|
|
|
|
|
I never knew the 'n and a half times loop', but essentially it is the same idea.
A couple disadvantages with your syntax: The exit statements are spread all over the loop code (if you have several 'EXITIF condition' and their associated statements spread throughout the loop. How do you indicate the end of an EXITCLAUSE?
Second: Several distinct / different EXITIF tests might require identical exit statements. When you directly follow the test with the exit statements, you might end up repeating the same code several times.
But all in all: The goal of this proposal closely resembles my exitfor/exitwhile idea.
|
|
|
|
|
Good lord, that seems complicated. How about:
if (mylist.Contains(refKey)
{
refKey.refcount++;
}
else
{
mylist.Insert(refKey);
refKey.refcount++;
}
since elt.key is the same object in your test if (elt.key == refkey) you can increment refKey's refcount.
Marc
|
|
|
|
|
OK, my point was not to illustrate how to insert an element into a list, but to illustrate a mechanism.
I just picked a very simple example 'off the top of my head' to show different exit handling - and as you point out: For that specific very simple example, there may be simpler ways to do it.
I could easily make a complex 50-line example to show the same mechanism in a composite context, but as a first presentation of the idea, it would clutter up the presentation. So I chose something simpler.
There certainly are cases where you have different exit handlers that can not be replaced by a predefined list method.
|
|
|
|
|
Member 7989122 wrote: OK, my point was not to illustrate how to insert an element into a list, but to illustrate a mechanism.
Ah, sorry. Sometimes I'm too literal.
Marc
|
|
|
|
|
I'll preface this by saying if you really want that syntax today, you could write that part of your program in Nemerle and use its macros to transform the syntax tree to your heart's content. I think that would let you create the kind of loop you're looking for. So you could write the class that performs the looping in Nemerle and just call it from C#/
To answer your question:
One disadvantage that comes to mind is that the change would encourage the use of loops where they're unnecessary, and would also encourage the use of the wrong data structure to solve a given problem. I think that loops with multiple break/exit conditions are usually an antipattern; if a coworker has to modify it (or you have to come back and modify it after 6+ months), the reasons for the conditional exits aren't always clear.
In the example you gave, the loop goes through the entire list every time you want to bump a reference count. If the list is relatively small, it's not a huge problem. If the list becomes large, then the O(n) lookup every time is going to hurt.
Instead, you could do something like:
public class ElementReferenceCounter
{
private readonly Dictionary<string, ListElt> elements;
public Elements()
{
elements = new Dictionary<string, ListElt>();
}
public void AddOrIncrementRefCount(string refKey)
{
if (elements.ContainsKey(refKey))
{
elements[refKey].RefCount++;
}
else
{
elements[refKey] = new ListElt(refKey, 0);
}
}
public void DecrementRefCount(string refKey)
{
if (!elements.ContainsKey(refKey)) return;
if(elements[refKey].RefCount == 1)
{
elements.Remove(refKey);
}
else
{
elements[refKey].RefCount--;
}
}
}
And you get O(1) list element lookup, at the expense of slightly higher memory use. More importantly, the interface is easy to understand. Anyone who works on the code in the future will see a call like
myList.AddOrIncrementRefCount(refkey) and immediately know the code's intent. It's easier to write tests for it this way, too.
In the future, if you found that you need to have your reference counter backed by a HashSet or a List instead of a Dictionary, go ahead and change it. As long as the class interface and behaviour stays the same, any code that uses it will just work without any changes.
I realize all that code is really specific to your example, and what you're proposing would be usable in a much wider variety of scenarios. It just seems that in most of those scenarios, there are probably more testable and maintainable ways to solve the problem.
In summation: what you propose isn't crazy and wouldn't cause major problems for the language, but it would encourage hard to maintain code. That by itself doesn't make this a bad idea...but you did ask for disadvantages, and that's one that came to mind.
|
|
|
|
|