PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.cplus > Re: YAPL - Yet Another Programming Language
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Re: YAPL - Yet Another Programming Language

Réponse
 
LinkBack Outils de la discussion
Vieux 30/06/2008, 16h43   #1
Juha Nieminen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

Adem24 wrote:
> 1) There is no goto statement.
> Hidden goto's like break- and continue-statements are also omitted.
>
> 2) There is no return statement.
> Instead a result variable can be declared to which the result of a function can be assigned.


Is the goal of this language to make the life of programmers as hard
as possible? Something like this becomes difficult to implement:

// Find the first value in 'data' which meets the requirements imposed
// by the parameter:
Type1 foo(Type2 value)
{
for(size_t i = 0; i < data.size(); ++i)
for(size_t j = 0; j < data[i].size(); ++j)
for(size_t k = 0; k < data[i][j].size(); ++k)
if(meetsRequirements(data[i][j][k], value)
return data[i][j][k];
}
  Réponse avec citation
Vieux 30/06/2008, 20h50   #2
thomas.mertes@gmx.at
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

On 30 Jun., 17:43, Juha Nieminen <nos...@thanks.invalid> wrote:
> Adem24 wrote:
> > 1) There is no goto statement.
> > Hidden goto's like break- and continue-statements are also omitted.

>
> > 2) There is no return statement.
> > Instead a result variable can be declared to which the result of a function can be assigned.

>
> Is the goal of this language to make the life of programmers as hard
> as possible? Something like this becomes difficult to implement:
>
> // Find the first value in 'data' which meets the requirements imposed
> // by the parameter:
> Type1 foo(Type2 value)
> {
> for(size_t i = 0; i < data.size(); ++i)
> for(size_t j = 0; j < data[i].size(); ++j)
> for(size_t k = 0; k < data[i][j].size(); ++k)
> if(meetsRequirements(data[i][j][k], value)
> return data[i][j][k];
>
> }

Your function returns garbage when nothing meets the requirements.
Your solution may be elegant, but it is wrong (I know that it can
be fixed easily). Some people would even argue that with structured
programming such bugs would not happen.
Besides that, I got your point.

Before going to the details let me explain the advantage when every
statement has exactly one entry and one exit (this is a side effect
of structured programming without any form of goto's):

If you want to add code that should be executed when the function
is left (e.g. some trace statement) you can just add it at the end
of the function. The only reason that your trace code is skipped is
when an exception is raised and no exception handler inside the
function catches it. If there are no exceptions you know that the
flow of control is always stuctured. If you jump around in your
code with gotos and returns you don't have this guarantee.

A stuctured solution to your example could use a boolean flag which
is changed when the data is found. It can be argued that this is
slower but todays compiler optimisations should not be
unerestimated. A C version of this structured function would be:

// Find the first value in 'data' which meets the requirements
// imposed by the parameter:
Type1 foo (Type2 value)
{
int search = 1;
Type1 result = Type1default;

for (size_t i = 0; i < data.size() & search; ++i) {
for (size_t j = 0; j < data[i].size() & search; ++j) {
for (size_t k = 0; k < data[i][j].size() & search; ++k) {
if (meetsRequirements(data[i][j][k], value) {
result = data[i][j][k];
search = 0;
}
}
}
}
return result;
}

As you can see, I prefer to use curly braces even when they are not
necessary. This use of curly braces allowes that statements
belonging to 'while', 'do', 'for' and 'if' statements can always be
added or removed without unintentionally changing the logic. The
use of a result variable makes clear which function holds the
result of the function. Since C needs a return statement I just put
it in front of the closing curly brace. IMHO a good compiler can
produce code which is as fast as your version.

In a language which has no C for loops like Seed7 the function
would look as follows:

const func Type1: foo (in Type2: aValue) is func
result
var Type1: result is Type1.value;
local
var integer: i is 1;
var integer: j is 1;
var integer: k is 1;
var boolean: search is TRUE;
begin
while i <= maxIdx(data) and search do
while j <= maxIdx(data[i]) and search do
while k < maxIdx(data[i][j]) and search do
if meetsRequirements(data[i][j][k], aValue) then
result := data[i][j][k];
search := FALSE;
end if;
incr(k);
end while;
incr(j);
end while;
incr(i);
end while;
end func;

I know that this solution is not as elegant.
Maybe I should introduce an advanced version of the 'for' statement
like:

for i range minIdx(data) range maxIdx(data) andWhile search do

What do you think?

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.
  Réponse avec citation
Vieux 01/07/2008, 18h29   #3
Juha Nieminen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

thomas.mertes@gmx.at wrote:
>> Type1 foo(Type2 value)
>> {
>> for(size_t i = 0; i < data.size(); ++i)
>> for(size_t j = 0; j < data[i].size(); ++j)
>> for(size_t k = 0; k < data[i][j].size(); ++k)
>> if(meetsRequirements(data[i][j][k], value)
>> return data[i][j][k];
>>
>> }

> Your function returns garbage when nothing meets the requirements.


Most compilers will issue a warning, though.

> A stuctured solution to your example could use a boolean flag which
> is changed when the data is found.


Exactly how is that different from 'break'? (Let's assume a 'break'
which can take as parameter how many nested loops it breaks from, like
some languages have. In other words, you could do a "break 3;" in the
example above, assuming it was supported.)

The only difference I can see is that the 'break' would be
compiler-supported (and thus easier for the compiler to optimize), while
the boolean solution is user-written, which is more work and clumsier.
Also, I don't believe the boolean solution would make the code any
easier to understand and follow than the 'break' solution.

> // Find the first value in 'data' which meets the requirements
> // imposed by the parameter:
> Type1 foo (Type2 value)
> {
> int search = 1;
> Type1 result = Type1default;
>
> for (size_t i = 0; i < data.size() & search; ++i) {
> for (size_t j = 0; j < data[i].size() & search; ++j) {
> for (size_t k = 0; k < data[i][j].size() & search; ++k) {
> if (meetsRequirements(data[i][j][k], value) {
> result = data[i][j][k];
> search = 0;
> }
> }
> }
> }
> return result;
> }


Another point: Assume that initializing the return value is a very
heavy operation. If a result is found, you are initializing the return
value twice, for no reason. (If the found value was returned from inside
the loop, and if the loops end without result, the default value is
returned, the return value would then always be initialized only once.)
In fact, it would be enough for the default value to be very heavy to
construct for this problem to happen.

Sure, you could add yet another boolean to take care of that... Is
this supposed to make the code easier to write and read, and/or less
error-prone?

> As you can see, I prefer to use curly braces even when they are not
> necessary.


That's mostly a matter of style and preference. I omitted them mostly
for brevity (ie. it doesn't mean I consistently avoid the braces in real
code whenever I can).

Btw, why do you use the braces in an inconsistent way?

> In a language which has no C for loops like Seed7 the function
> would look as follows:
>
> const func Type1: foo (in Type2: aValue) is func
> result
> var Type1: result is Type1.value;
> local
> var integer: i is 1;
> var integer: j is 1;
> var integer: k is 1;
> var boolean: search is TRUE;
> begin
> while i <= maxIdx(data) and search do
> while j <= maxIdx(data[i]) and search do
> while k < maxIdx(data[i][j]) and search do
> if meetsRequirements(data[i][j][k], aValue) then
> result := data[i][j][k];
> search := FALSE;
> end if;
> incr(k);
> end while;
> incr(j);
> end while;
> incr(i);
> end while;
> end func;


I'm sorry but I have to confess that doesn't look like very attractive
to me. The 9 lines of code in my original function (with the fix of
returning the default value at the end) vs. 23 lines in your example. I
honestly can't say your version is more readable either.

Let's make it clear that I'm all against compact obfuscated code.
However, there's a limit where code becomes *too* verbose to be comfortable.

> I know that this solution is not as elegant.
> Maybe I should introduce an advanced version of the 'for' statement
> like:
>
> for i range minIdx(data) range maxIdx(data) andWhile search do
>
> What do you think?


A 'for' clause is always a handy shortcut for 'while', so why not.

I also think you should really consider 'break' (perhaps even the
version which takes a parameter, as I mentioned above).
  Réponse avec citation
Vieux 02/07/2008, 09h25   #4
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

[I've removed comp.lang.c from the cross-postings, since the
syntax of the proposed solutions is purely C++.]

On Jul 1, 7:29 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> thomas.mer...@gmx.at wrote:
> >> Type1 foo(Type2 value)
> >> {
> >> for(size_t i = 0; i < data.size(); ++i)
> >> for(size_t j = 0; j < data[i].size(); ++j)
> >> for(size_t k = 0; k < data[i][j].size(); ++k)
> >> if(meetsRequirements(data[i][j][k], value)
> >> return data[i][j][k];


> >> }

> > Your function returns garbage when nothing meets the requirements.


> Most compilers will issue a warning, though.


> > A stuctured solution to your example could use a boolean flag which
> > is changed when the data is found.


> Exactly how is that different from 'break'?


It gives a name to the condition, and makes it clear to the
reader what is going on. However...

A structured solution would break this down into several
functions. In the next release of C++ (with lambda), you could
easily do the whole thing with a single call to std::find_if:
the predicate for std::find_if on the outer dimension would
invoke std::find_if on the next dimention, and so on.

Alternatively, since you're really doing a linear search over
the flattened structure, you'd use an iterator which flattened
the structure. I'm pretty sure that Boost has something which
would here.

> (Let's assume a 'break' which can take as parameter how many
> nested loops it breaks from, like some languages have. In
> other words, you could do a "break 3;" in the example above,
> assuming it was supported.)


That is, of course, a real trap. Change the structure, and your
code silently changes meaning. Having a one level break is bad
enough.

> The only difference I can see is that the 'break' would be
> compiler-supported (and thus easier for the compiler to
> optimize), while the boolean solution is user-written, which
> is more work and clumsier. Also, I don't believe the boolean
> solution would make the code any easier to understand and
> follow than the 'break' solution.


> > // Find the first value in 'data' which meets the requirements
> > // imposed by the parameter:
> > Type1 foo (Type2 value)
> > {
> > int search = 1;
> > Type1 result = Type1default;


> > for (size_t i = 0; i < data.size() & search; ++i) {
> > for (size_t j = 0; j < data[i].size() & search; ++j) {
> > for (size_t k = 0; k < data[i][j].size() & search; ++k) {
> > if (meetsRequirements(data[i][j][k], value) {
> > result = data[i][j][k];
> > search = 0;
> > }
> > }
> > }
> > }
> > return result;
> > }


> Another point: Assume that initializing the return value is a very
> heavy operation.


Why? Since I have to consider the possibility of not finding
the value, I'd use a Fallible:

Fallible< Type1 > result ;
for ( size_t i = 0 ; ! result.isValid() && i != data.size() ; ++
i ) {
for ( size_t j = 0 ; ! result.isValid() && j != data.size() ; +
+ j ) {
for ( size_t k = 0 ; ! result.isValid() && k !=
data.size() ; ++ k ) {
if ( meetsRequirements( data[ i ][ j ][ k ], value ) {
result.validate( data[ i ][ j ][ k ] ) ;
}
}
return result ;

Initializing a Fallible to invalide is a very cheap operation,
involving setting a boolean flag (and nothing else in my current
implementations).

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
  Réponse avec citation
Vieux 02/07/2008, 14h55   #5
Juha Nieminen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

James Kanze wrote:
>>>> Type1 foo(Type2 value)
>>>> {
>>>> for(size_t i = 0; i < data.size(); ++i)
>>>> for(size_t j = 0; j < data[i].size(); ++j)
>>>> for(size_t k = 0; k < data[i][j].size(); ++k)
>>>> if(meetsRequirements(data[i][j][k], value)
>>>> return data[i][j][k];

>
>>>> }


> A structured solution would break this down into several
> functions.


How exactly would that ? The calling function would still have to
check if the called function found the value or not, and end the loop if
so. But of course, loops cannot be ended from inside, except with the
boolean variable. So how is this a better solution?

> In the next release of C++ (with lambda), you could
> easily do the whole thing with a single call to std::find_if:
> the predicate for std::find_if on the outer dimension would
> invoke std::find_if on the next dimention, and so on.


The outer dimension would still have to stop if the inner dimension
found the value. How does it do that?

> That is, of course, a real trap. Change the structure, and your
> code silently changes meaning. Having a one level break is bad
> enough.


I prefer breaks over having to use extraneous useless booleans which
do nothing but make the code less readable, and possibly even less
efficient.

It's not like breaks would stop you from doing it in a purely
structured manner. They are optional.
  Réponse avec citation
Vieux 02/07/2008, 16h48   #6
Willem
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

Juha Nieminen wrote:
) James Kanze wrote:
)> In the next release of C++ (with lambda), you could
)> easily do the whole thing with a single call to std::find_if:
)> the predicate for std::find_if on the outer dimension would
)> invoke std::find_if on the next dimention, and so on.
)
) The outer dimension would still have to stop if the inner dimension
) found the value. How does it do that?

In a hypothetical language, where this is a 'lambda' function with single
parameter, called 'a', returning the value of do_something_with:

{ a | do_something_with(a) }

And 'or' is a shortcut operator so that a or b equals a ? a : b

This finds the first result in an array:

find_it = { arr, func |
if (arr) { func(arr[0]) or find_it(arr[1..], func) }
else { undef }
}
result = find_it(array, { a| meetsReqs(a) ? a : undef } );

And this is a way to find the first result in a 3-D array:

result = find_it(array3, { array2 |
find_it(array2, { array1 |
find_it(array1, { a| meetsReqs(a) ? a : undef })
})
});

But, of course, given an is_array() function, this finds the first result
in an N-dimensional array:

array_find = { func, a |
if (is_array(a)) { find_it(a, array_find(func)) or undef }
else { func(a) or undef }
}
result = find_it(array, array_find(func));

NB: The result of calling a function with less arguments is a function
where those arguments are filled in. For example, if plus() adds
its two arguments then you can do: increase2 = plus(2);

Lots of features, huh ? But languages have existed for a long time that
have all of them. Some of them even resemble C. (Say, LPC)


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
  Réponse avec citation
Vieux 02/07/2008, 17h27   #7
Juha Nieminen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

Willem wrote:
> In a hypothetical language, where this is a 'lambda' function with single
> parameter, called 'a', returning the value of do_something_with:
>
> { a | do_something_with(a) }
>
> And 'or' is a shortcut operator so that a or b equals a ? a : b
>
> This finds the first result in an array:
>
> find_it = { arr, func |
> if (arr) { func(arr[0]) or find_it(arr[1..], func) }
> else { undef }
> }
> result = find_it(array, { a| meetsReqs(a) ? a : undef } );
>
> And this is a way to find the first result in a 3-D array:
>
> result = find_it(array3, { array2 |
> find_it(array2, { array1 |
> find_it(array1, { a| meetsReqs(a) ? a : undef })
> })
> });
>
> But, of course, given an is_array() function, this finds the first result
> in an N-dimensional array:
>
> array_find = { func, a |
> if (is_array(a)) { find_it(a, array_find(func)) or undef }
> else { func(a) or undef }
> }
> result = find_it(array, array_find(func));


This starts resembling Haskell. Exactly as obfuscated.
  Réponse avec citation
Vieux 02/07/2008, 17h58   #8
Willem
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: YAPL - Yet Another Programming Language

Juha Nieminen wrote:
) This starts resembling Haskell. Exactly as obfuscated.

Actually, I had Perl in mind when I was writing it, although I was very
liberal in how I wrote stuff, so the resemblance is small.

Talking about Perl, obfuscated, and functions, how about this piece
of code, demonstrating ADT and data hiding:

sub create_stack
{
my @stack; # Only accessible from within this function, right ?
return ( sub { push @stack, @_ }, sub { pop @stack } );
}

my ($pusher, $popper) = create_stack();

$pusher->('x');
$pusher->('y');
print $popper->();
$pusher->('z');
print $popper->();
print $popper->();


Who needs OOP ? :-)


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 02h43.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,26695 seconds with 16 queries