August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andre Artus | On Monday, 5 August 2013 at 04:07:55 UTC, Andre Artus wrote:
>
>>> Andre Artus:
>>> int number;
>>> string message;
>>> switch (number)
>>> {
>>> default: // valid: ends with 'throw'
>>> throw new Exception("unknown number");
>>> case 3:
>>> message ~= "three "; break;
>>> case 4:
>>> message ~= "four "; continue;
>>> case 5:
>>> message ~= "five "; goto case;
>>> case 6:
>>> message ~= "six "; break;
>>> case 1:
>>> case 2:
>>> message = "one or two";
>>> }
>>>
>>> With the inclusion of 'default' the condition covers the whole range of 'int'. The programmer may only want the pre and post code to be executed for every other case (1..6).
>
>> MattCoder:
>> Like I said, it would be nice if we could extend some D features without change the compiler source, maybe like macros in LISP.
>
> It may not always be the case, but in my experience this often leads to write-only code.
> I'm pretty new to D, so I'm not quite up to speed with the metaprogramming abilities, but I'm under the impression that this is what mixin's are for.
Well I'm not experienced too, but mixin's for what I know just works in compiler time right?
But anyway it would be possible to write my own switch version with mixin? I really would like to see this.
Matheus.
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to dennis luehring | On Monday, 5 August 2013 at 09:37:11 UTC, dennis luehring wrote:
> this type of sub-branching "de-looping" is slow (if performance is relevant) and just not foreach-able, and so not functional-style programming - its called "for loop index micro management for unknown reasons" - but many programmers prefer it very much :)
It's caused by lack of inner functions in many languages - people use switch+flags or for loops to be more DRY.
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to QAston | On Monday, 5 August 2013 at 11:32:14 UTC, QAston wrote:
> On Monday, 5 August 2013 at 09:37:11 UTC, dennis luehring wrote:
>
>> this type of sub-branching "de-looping" is slow (if performance is relevant) and just not foreach-able, and so not functional-style programming - its called "for loop index micro management for unknown reasons" - but many programmers prefer it very much :)
>
> It's caused by lack of inner functions in many languages - people use switch+flags or for loops to be more DRY.
I was under the impression that D has nested functions, unless by inner function you mean something else.
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to MattCodr | >> Andre Artus: >> >> It may not always be the case, but in my experience this often leads to write-only code. >> I'm pretty new to D, so I'm not quite up to speed with the metaprogramming abilities, but I'm under the impression that this is what mixin's are for. > MattCoder: > > Well I'm not experienced too, but mixin's for what I know just works in compiler time right? > > But anyway it would be possible to write my own switch version with mixin? I really would like to see this. > > Matheus. Yes, it takes any string that's valid D. I see people using it to embed domain specific languages (e.g. PEG via PEGGED) so you should easily be able to write a translator/preprocessor that takes your switch and converts it to D code. mixin(" switch (number) { default: // valid: ends with 'throw' throw new Exception("unknown number"); common_entry: // some common entry code break; common_exit: // some common exit code break; case 3: message ~= "three "; break; case 4: message ~= "four "; continue; case 6: message ~= "six "; break; } "); The preprocessor could rewrite to this string: " switch (number) { case 3: case 4: case 6: // some common entry code break; } switch (number) { default: // valid: ends with 'throw' throw new Exception("unknown number"); case 3: message ~= "three "; break; case 4: message ~= "four "; continue; case 6: message ~= "six "; break; } switch (number) { case 3: case 4: case 6: // some common exit code break; } " **** I do not recommend anyone do this **** The reason I would not recommend this is that it leads to brittle code that is hard to debug and reason about. The reason I use `switch`, and not `if` for the entry and exit code is because these should only fire under the same conditions as the cases in the original switch, otherwise you introduce hard to find bugs in your code. Once again, I do not recommend people doing this: my preference is for code that makes the programmers intent clear and explicit. |
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to dennis luehring | On Monday, 5 August 2013 at 09:37:11 UTC, dennis luehring wrote:
> Am 05.08.2013 08:28, schrieb luminousone:
>> or perhaps
>>
>> for( int i = 0 ; i < 10 ; i ++ )
>> in {
>> assert( i == 0 );
>> }
>> out {
>> assert( i == 9 );
>> }
>> body {
>> ... stuff ...
>> }
>
> that is just evil code
>
> if you got something todo before or on the first item of the list do it before the loop - and for the last behind the for loop
>
> if we talk about code-duplication then - use an inner function
>
> this type of sub-branching "de-looping" is slow (if performance is relevant) and just not foreach-able, and so not functional-style programming - its called "for loop index micro management for unknown reasons" - but many programmers prefer it very much :)
I have been programming since '92 and I must say that I have never seen this before. Maybe I've just been lucky, but this kind of thing would never pass a review anywhere I have worked before. Code is a user interface, if the user's model differs from the system model you will get errors. I.e. Junior von Newhire should be able to correctly reason about any piece of the code from day one. If they cannot do so they will introduce bugs.
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andre Artus | On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
> On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
>> perhaps a more generic solution should be looked at, extend contracts to work with all scope blocks.
>>
>> switch(somenumber)
>> in {
>> ... before stuff ...
>> }
>> out {
>> .... after stuff ...
>> }
>> body {
>> case 1:
>> in {
>> ... etc ....
>> }
>> out {
>> ... more etc ...
>> }
>> body {
>> ...
>> }
>> case 2:
>> // and so on
>> }
>>
>> or perhaps
>>
>> for( int i = 0 ; i < 10 ; i ++ )
>> in {
>> assert( i == 0 );
>> }
>> out {
>> assert( i == 9 );
>> }
>> body {
>> ... stuff ...
>> }
>>
>> if it is desired for a particular contract block to be called in release builds perhaps a attribute label to mark it as a runtime block or something similar.
>>
>> foreach( i, k ; somerange )
>> @runtime in {
>> ...
>> }
>> body {
>> }
>
> Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming.
>
>
> The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that.
>
> At the bottom of this page you can find a reading list for more info.
> http://www.digitalmars.com/d/dbc.html
>
> Or for a general overview:
> http://en.wikipedia.org/wiki/Design_by_contract
>
> Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?
None taken, =-p.
I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function.
void a() {
int i = 0;
void b()
in {
assert( i == 0 );
}
out {
assert( i == 10 );
}
body {
for( ; i < 10 ; i ++ ) {
... do something ...
}
}
b();
}
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to ron | On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote:
> On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
>> On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
>>> perhaps a more generic solution should be looked at, extend contracts to work with all scope blocks.
>>>
>>> switch(somenumber)
>>> in {
>>> ... before stuff ...
>>> }
>>> out {
>>> .... after stuff ...
>>> }
>>> body {
>>> case 1:
>>> in {
>>> ... etc ....
>>> }
>>> out {
>>> ... more etc ...
>>> }
>>> body {
>>> ...
>>> }
>>> case 2:
>>> // and so on
>>> }
>>>
>>> or perhaps
>>>
>>> for( int i = 0 ; i < 10 ; i ++ )
>>> in {
>>> assert( i == 0 );
>>> }
>>> out {
>>> assert( i == 9 );
>>> }
>>> body {
>>> ... stuff ...
>>> }
>>>
>>> if it is desired for a particular contract block to be called in release builds perhaps a attribute label to mark it as a runtime block or something similar.
>>>
>>> foreach( i, k ; somerange )
>>> @runtime in {
>>> ...
>>> }
>>> body {
>>> }
>>
>> Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming.
>>
>>
>> The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that.
>>
>> At the bottom of this page you can find a reading list for more info.
>> http://www.digitalmars.com/d/dbc.html
>>
>> Or for a general overview:
>> http://en.wikipedia.org/wiki/Design_by_contract
>>
>> Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?
>
> None taken, =-p.
>
> I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function.
>
> void a() {
> int i = 0;
> void b()
> in {
> assert( i == 0 );
> }
> out {
> assert( i == 10 );
> }
> body {
> for( ; i < 10 ; i ++ ) {
> ... do something ...
> }
> }
> b();
> }
Speaking of contracts, and reading the docs I see:
"Pre and Post Contracts
The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has..."
So are contracts possible outside function declarations? For example just scopes or random places in code.
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to Borislav Kosharov | On Monday, 5 August 2013 at 20:45:47 UTC, Borislav Kosharov wrote:
> On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote:
>> On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
>>> On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
>>>> perhaps a more generic solution should be looked at, extend contracts to work with all scope blocks.
>>>>
>>>> switch(somenumber)
>>>> in {
>>>> ... before stuff ...
>>>> }
>>>> out {
>>>> .... after stuff ...
>>>> }
>>>> body {
>>>> case 1:
>>>> in {
>>>> ... etc ....
>>>> }
>>>> out {
>>>> ... more etc ...
>>>> }
>>>> body {
>>>> ...
>>>> }
>>>> case 2:
>>>> // and so on
>>>> }
>>>>
>>>> or perhaps
>>>>
>>>> for( int i = 0 ; i < 10 ; i ++ )
>>>> in {
>>>> assert( i == 0 );
>>>> }
>>>> out {
>>>> assert( i == 9 );
>>>> }
>>>> body {
>>>> ... stuff ...
>>>> }
>>>>
>>>> if it is desired for a particular contract block to be called in release builds perhaps a attribute label to mark it as a runtime block or something similar.
>>>>
>>>> foreach( i, k ; somerange )
>>>> @runtime in {
>>>> ...
>>>> }
>>>> body {
>>>> }
>>>
>>> Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming.
>>>
>>>
>>> The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that.
>>>
>>> At the bottom of this page you can find a reading list for more info.
>>> http://www.digitalmars.com/d/dbc.html
>>>
>>> Or for a general overview:
>>> http://en.wikipedia.org/wiki/Design_by_contract
>>>
>>> Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?
>>
>> None taken, =-p.
>>
>> I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function.
>>
>> void a() {
>> int i = 0;
>> void b()
>> in {
>> assert( i == 0 );
>> }
>> out {
>> assert( i == 10 );
>> }
>> body {
>> for( ; i < 10 ; i ++ ) {
>> ... do something ...
>> }
>> }
>> b();
>> }
>
> Speaking of contracts, and reading the docs I see:
> "Pre and Post Contracts
>
> The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has..."
>
> So are contracts possible outside function declarations? For example just scopes or random places in code.
I being zero is the precondition for that loop, and i being 10 is the post condition for that loop.
Pretty much I think that any scope can potentially fit the definition for contracts.
Really any block of code, can be considered to have pre and post conditions, functions just happen to be one way to organize code.
|
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to ron | On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote: > On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote: >> On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote: >>> perhaps a more generic solution should be looked at, extend contracts to work with all scope blocks. >>> >>> switch(somenumber) >>> in { >>> ... before stuff ... >>> } >>> out { >>> .... after stuff ... >>> } >>> body { >>> case 1: >>> in { >>> ... etc .... >>> } >>> out { >>> ... more etc ... >>> } >>> body { >>> ... >>> } >>> case 2: >>> // and so on >>> } >>> >>> or perhaps >>> >>> for( int i = 0 ; i < 10 ; i ++ ) >>> in { >>> assert( i == 0 ); >>> } >>> out { >>> assert( i == 9 ); >>> } >>> body { >>> ... stuff ... >>> } >>> >>> if it is desired for a particular contract block to be called in release builds perhaps a attribute label to mark it as a runtime block or something similar. >>> >>> foreach( i, k ; somerange ) >>> @runtime in { >>> ... >>> } >>> body { >>> } >> >> Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. >> >> >> The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. >> >> At the bottom of this page you can find a reading list for more info. >> http://www.digitalmars.com/d/dbc.html >> >> Or for a general overview: >> http://en.wikipedia.org/wiki/Design_by_contract >> >> Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check? > > None taken, =-p. > > I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function. > > void a() { > int i = 0; > void b() > in { > assert( i == 0 ); > } > out { > assert( i == 10 ); > } > body { > for( ; i < 10 ; i ++ ) { > ... do something ... > } > } > b(); > } I could be missing something, if so please clarify. The construct I have issue with is this one, >>> switch(somenumber) >>> in { >>> ... before stuff ... >>> } >>> out { >>> .... after stuff ... >>> } I would contend that code within in/out/invariant blocks should be 'pure' (no state changes, no IO [other than assert throwing]), it's only there to validate that a class and it's methods do not violate certain conditions. They should be able to be stripped out of the release build without altering the execution of the application in any way. A classic example is the null dereference check, which some compilers and most (all?) static analysers can detect. string whoIsAMonkey(Person p) in { assert(p !is null, "Person can not be null"); assert(!isNullOrEmpty(p.Name), "Person name can not be null or empty"); } body { return p.Name ~ " is a monkey!"; } void main() { Person p = null; // Compiler / analyser should complain with // "Person can not be null" writeln(whoIsAMonkey(p)); // ^ here } void main() { Person p = new Person(); // Compiler / analyser should complain with // "Person name can not be null or empty" writeln(whoIsAMonkey(p)); } etc. Contracts are meant to define the public (*) interface of a class. * By public I mean here anything not 'private', e.g. 'protected' for inheritance. As Andrei points out in his book ("The D Programming Language") contracts are not used to validate/scrub user (or any external) input as they can be compiled out of the executable. Contracts are there to check sanity at compile time, or at the very least during testing. The contract is (or should be) part of the documentation. |
August 05, 2013 Re: request switch statement with common block | ||||
---|---|---|---|---|
| ||||
Posted in reply to Borislav Kosharov | > Borislav Kosharov wrote:
>
> Speaking of contracts, and reading the docs I see:
> "Pre and Post Contracts
>
> The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has..."
>
> So are contracts possible outside function declarations? For example just scopes or random places in code.
They should not be. Other than the 'invariant' which is on the class/interface.
|
Copyright © 1999-2021 by the D Language Foundation