Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^3: I'm trying to consolidate my functions into subroutines

by RonW (Parson)
on May 16, 2017 at 23:26 UTC ( [id://1190413]=note: print w/replies, xml ) Need Help??


in reply to Re^2: I'm trying to consolidate my functions into subroutines
in thread I'm trying to consolidate my functions into subroutines

Except subroutines are supposed to be reusable.

What LanX means is that a function is a subroutine. Specifically, a subroutine that returns a value (or a list of values).

In Perl, all subroutines return a value, either explicitly or implicitly, so all Perl subroutines are also functions.

So, the following 3 definitions are equivalent:

sub myfunction_long { my $z = $_[0] + $_[1]; # add the first 2 parameters and assign res +ult to $z return $z; } sub myfunction_medium { my $z = $_[0] + $_[1]; # add the first 2 parameters and assign res +ult to $z } # value of $z implicitly returned sub myfunction_short { $_[0] + $_[1]; # add the first 2 parameters } # result of expression implicitly returned print myfunction_long(1, 2); # prints 3 print myfunction_medium(1, 2); # prints 3 print myfunction_short(1, 2); # prints 3

Many people are more comfortable using return even when not needed. When not used, the result of the last executed statement is the value returned.

In some programming languages, such as C, you can define either a "pure" subroutine or a function:

In some programming languages, such as C, you can define either a function or a "pure" subroutine:

int z = 0; void myroutine(int x, y) // "void" tells the compiler that no value is + returned { z = x + y; // add the values of the 2 defined parameters and assig +n the result to the global z } int myfunction(int x, y) // "int" tells the compiler that an integer v +alue is returned { return(x + y); // add the values of the 2 defined parameters then +return the result }

Perl, however, has no such distinction.

Update: Changed order of terms in a sentence to limit scope of the adjective "pure".

Replies are listed 'Best First'.
Re^4: I'm trying to consolidate my functions into subroutines
by AnomalousMonk (Archbishop) on May 17, 2017 at 03:11 UTC
    ... a function is a subroutine ... that returns a value (or a list of values).

    In general, your distinction between function and subroutine as, respectively, returning or not returning a value seems of little use. Is there really any formal distinction here in any language?

    In some programming languages, such as C, you can define either a "pure" subroutine or a function ...

    I'm confused by your use of the term "pure" as it relates to subroutines/functions. As I understand it, a pure function is one whose behavior is not affected in any way by the state of the system in which it's running, has no effect upon the system other than by its return value, and creates no persistent state; the function has no "side effects." Any language can have such functions. As such, a pure function returning void would be useless. (Some languages allow the definition of functions with a pure attribute and purity is enforced by the compiler, but I'm not aware that ISO-C is one of them; I may be behind the latest standard here. (FWIW, a little Googling shows that GNU C has an  __attribute__ "pure" feature.)) Your  myfunction() C function is operationally pure; your  myroutine() function is not: it has the side effect of assignment to the  z variable and the effect of this assignment persists after the function terminates execution. (All three of the Perl functions you give as examples are operationally pure, but as you say, Perl neither defines nor enforces any formal notion of function purity.)

    Update: See the discussion of the implementation of Pure Functions in the D language.


    Give a man a fish:  <%-{-{-{-<

      > Is there really any formal distinction here in any language?

      Pascal has function versus procedure.

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      Is there really any formal distinction here in any language?

      Certainly in Fortran at least there is. The declarative statements FUNCTION and SUBROUTINE define two different types of subprogram. The former returns a value and is invoked like

      X = SIN(Y)

      whereas the latter does not and is invoked like

      CALL RANDOM_NUMBER(A)

      They serve distinct purposes. HTH.

      Re^5: I'm trying to consolidate my functions into subroutines and Re^5: I'm trying to consolidate my functions into subroutines are already good answers.

      Old home computer BASICs (those with line numbers, e.g. C64, ZX 81, ZX Spectrum) have functions and subroutines. Functions (like SIN, COS, PEEK, RAND) are build-in, and there is usually no way to create user-defined functions. Procedures are simply some lines of code called by GOSUB and ending with RETURN, not able to return a value except by modifying global variables.

      Pascal and Fortran share the distinction between functions and procedures, forcing the programmer to check the return value, or at least use it in some way. Common workarounds are IFs without any code in the THEN block, or using the unwanted return value as input for a procedure with nearly no side-effects. In Sinclair BASICs (see below), you often see RAND USR 16514 to call machine code at address 16514 and discarding the return value. Actually, the return value is used to initialise the random number generator. But often, the machine code simply does not return, and so even PRINT USR 16514 can be found.

      C and C++ have, from a syntactical point of view, only functions. But strictly speaking, any function returning void does just that: It returns nothing and thus is a procedure. Unlike Pascal, Fortran, and the old home computer BASICs, C and C++ allow calling any function like a procedure (i.e. fooBar(); instead of someVar=fooBar();), discarding any return value. This is the source of many bugs, because often functions return an error code or a success indicator; and lazy programmers tend to ignore the possibility of an error, especially in seemingly trivial functions. It is even possible to call procedures as function. Of course, this results in undefined behavior, but gcc accepts that without any warnings, even with -Wall and -pedantic. The logic is simple: You are the programmer, you are explicitly casting, so you must know what you are doing.

      /tmp>cat evil.c #include <stdio.h> #include <stdlib.h> typedef int (*func_returning_int)(void); typedef void (*func_returning_void)(void); void dummy(void) { puts("Hello World"); } int main(int argc, char ** argv) { func_returning_void f = &dummy; int i = 0; f(); i = ((func_returning_int)f)(); printf("i=%i\n",i); return 0; } /tmp>CFLAGS="-Wall -pedantic" make evil cc -Wall -pedantic evil.c -o evil /tmp>./evil Hello World Hello World i=12 /tmp>

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        It is even possible to call procedures as function. Of course, this results in undefined behavior,

        C99 says,

        If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
        (There is, however, an exception for the main() function that has an implicit "return 0" before closing brace.)

        Further, the C standard does not define or use such terminology "procedure" or "subroutine". These words no not even appear in remarks or informal parts. I think this is a very deliberate choice.

        The logic or rationale behind those dangerous jump statements (goto/return/break/continue) is that the compiler is unable to follow the program flow or value propagation in the absolute sense. Gcc may warn that a variable may be used uninitialized, while the programmer can easily see this can not happen. The compiler may not even know if the return value was properly computed or if undefined behavior was somehow involved. Thus C does not prohibit questionable constructs such as goto into a scope of a variable (past its initialization).

        But note, even when "may be uninitialized" warning is a false positive, it has informational value for the programmer. It may signal a refactoring opportunity, such that would allow the compiler better insight into your program and possibly better code as a result.

      I should have worded it "a function or a 'pure' subroutine" as I only meant "pure" to apply to subroutine. By "pure subroutine", I mean it doesn't return a result. (Which necessarily means, to be useful, it has side effects.1)

      As for subroutines vs functions in C, it's really the absence or presence of a return statement that distinguishes a subroutine from a function. If there is no return statement, nothing will be returned. Many C compilers, if the returned type is not void will complain about the lack of a return statement. Likewise, will complain when a void routine does have a return

      I chose C because that's one of my 2 main programming languages (the other being Perl). I have passing familiarity with languages that make a more explicit distinction between subroutines and functions, such as Pascal (which another monk mentioned).

      ---

      1A real world example of a useful subroutine is:

      void Motor(int speed, enum eDIR dir) { ... }

      Which tells the hardware how fast and which direction to run a motor.

      what is an example of a Perl builtin or even in a module function that is pure?
        Mathematical functions like sqrt() are normally pure.

        Built-ins changing $_ or other globals like m// are not.

Re^4: I'm trying to consolidate my functions into subroutines
by Anonymous Monk on May 17, 2017 at 17:09 UTC

    As AnomalousMonk wrote, such function attributes are GNU C extensions. But they can be considered de facto standard features on many platforms. Excerpt from gcc info's:

    • const. Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the `pure' attribute below, since function is not allowed to read global memory....
    • pure. Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute `pure'. For example,
      int square (int) __attribute__ ((pure));
      says that the hypothetical function `square' is safe to call fewer times than the program says....
    Note that in many cases, the compiler can discover those attributes on its own (and even offer suggestions to the programmer via warnings.)

    ps. Take care not to confuse type qualifier const with attribute((const))

      gcc has more than just function attributes. Variables, types, labels, enums, and statements also can have attributes. They all share a common syntax, choosen in a way that the programmer can use a preprocessor macro to hide gcc attributes from a non-gcc compiler.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1190413]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (5)
As of 2024-03-29 10:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found