|
Home | Switchboard | Unix Administration | Red Hat | TCP/IP Networks | Neoliberalism | Toxic Managers |
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and bastardization of classic Unix |
Perl was developed as the language for processing logs for NSA, then emerged as the language of choice for elite Unix sysadmins, then enjoyed a short love affair with CGI programming but quickly was displaced by PHP (PHP started out as a set of "Perl hacks" and cloned many Perl features); Now Perl returned to its roots -- it again became the language for the elite Unix sysadmins
|
Murphy laws of engineering |
Higher level languages like Perl allow to use "defensive programming" paradigm more fully. So let's discuss this concept first as increasing the level of language makes defensive programming more feasible (number of bugs typically is proportional to the length of the program) and allow to implement the concept more fully.
Defensive programming is a style of programming which stems from programming style adopted by compiler writers who represent the elite of the programming community and includes such names as:
and many other. We can add several people who developed scripting language interpreters:
You can only design and write a few compilers from a reasonably complex language in your lifetime (Nicklaus Wirth manages to write three, and while the languages involved were not on the level of complexity of PL/1 or Perl, this probably is a record; Ken Thomson manages to create two C and Go). Besides the complexity of the code generation, in the past hardware moves ahead fast enough making some compromises during the design phase obsolete. So creating a solid architecture of a portable complier for a particular language means among other things correctly guessing trends in hardware for the next several years Writing a widely used compiler for a successful language is the high art of system programming. The art which can be mastered by a few especially gifted programmers.
The basic idea behind this approach is to write the program like a compiler so that it is able to run properly even through unforeseen input by users. In many ways, the concept of defensive programming is much like that of defensive driving, in that it tried to anticipate problems before they arise. One common feature is the ability handle strange input without crashing or, worse, creating a disaster.
In a way, defensive programming tried to eliminate many bugs before they happen. The classic example of "non-defensive" programming is the absence of checking of a return code for an external routine or some Unix utility. This type of bugs often slips into production code and they are discovered only during production runs, possibly many years from initial release of the product, often at a great cost. Just enforcement of the rule that no external module or utility can be used without checking its return code prevents many bugs from happening.
In general the deeper in development cycle you find the bug, the more costly it is for fix. So while defensive programming might produce some minor overhead in both source code lines count and the run time (which for system utilities does not matter at all) it dramatically cheapens the total development costs, as fewer bugs slip into most costly for detention and elimination stage: the production phase.
That essentially means that that the program is written in such way that it is able to able to protect itself against all invalid inputs. Which is the standard behaviour of the complier, but which can be extended to other types of programs. It also emphasizes the quality of diagnostic of wrong inputs and situations and "intelligent" dealing with those that still can guarantee the correct results.
The invalid inputs (aka bad data) can come from user input via the command line, as a result undetected errors on other parts of the program, as a special conditions related to various objects such as file (i/o error in the file, missing file, insufficient permissions, etc). Bad data can also come from other routines in your program via input parameters. Defensive programming is greatly facilitated by an awareness of specific, typical blunders (aka SNAFU), and vulnerabilities ( for example for sysadmin scripts and utilities a collection of "Horror Stories" exists; see for example Creative uses of rm )
In other words, defensive programming is about making the software work in a predictable manner in spite of unexpected inputs.
Another "re-incarnation" of this concept can be traced to the period of creation of ADA programming language (1977-1983) or even earlier in the context of writing real time software. Former DOD standard for large scale safety critical software development emphasized encapsulation, data hiding, strong typing of data, minimization of dependencies between parts to minimize impact of fixes and changes. Which is the right dose (determining of which requires programming talent) can improve the quality of programs and simplify ( but not necessary shorten ) the debugging and testing stages of program development.
One typical problem in large software modification is that creating changes by person who is not the original developer often damages conceptual integrity of the product. In this case fixing one problem creates multiple others still to be detected and fixed (one step forward, two steps back). One way to fight this problem of "increasing entropy with age" or loss of conceptual integrity is to institute a set of sanity checks which detect abnormal parameters values (assertions or some similar mechanism). In most systems resulting overhead is negligible as such check usually are administered outside the most inner loops. but the positive effect is great.
Many people independently came to the subset of ideas of defensive programming, so it is impossible to attribute this concept to a single author. As an example of early attempt to formulate some principles of defensive programming style we can list Tom Christiansen recommendations (Jan 1, 1998) for Perl language. Perl does not have strict typing of variables and, by default, does not require any declaration of variables, creating potential for misspelled variables slipping into production version of the program. (unless you use strict pragma -- the use the latter became standard in modern Perl). While they are more then 20 years old they are still relevant:
eval""
or s///ee
. else
after a chain of elsif
s Out of those the most interesting is taint option (strict is also interesting but it simply partially fixes oversights in the initial design of the language; Python uses more sound idea of typing values and requires explicit conversion between values of different types). Here is a quote from Perl Command-Line Options - Perl.com:
The final safety net is the
-T
option. This option puts Perl into "taint mode." In this mode, Perl inherently distrusts any data that it receives from outside the program's source -- for example, data passed in on the command line, read from a file, or taken from CGI parameters.Tainted data cannot be used in an expression that interacts with the outside world -- for example, you can't use it in a call to
system
or as the name of a file to open. The full list of restrictions is given in theperlsec
manual page.In order to use this data in any of these potentially dangerous operations you need to untaint it. You do this by checking it against a regular expression. A detailed discussion of taint mode would fill an article all by itself so I won't go into any more details here, but using taint mode is a very good habit to get into -- particularly if you are writing programs (like CGI programs) that take unknown input from users.
sub subindex inline{ $_[0]=substr($_[0],index($_[0],$_[1],$_[2])) }
for($var){
when($_ eq 'b'){ ...;} # means if ($var eq 'b') { ... ; last} when($_ >'c'){...;} } # for
my rc==0; for(...){ if (condition1) { $rc=1; last;} elsif(...){$rc=2; last} } if ($rc==0){...} elif($rc==1){...} elif($rc==3){...}
One possible implementation would be usage of Pascal-style local labels (limited to the block in which they are defined), each of which corresponds when in the loop body in that particular order. default local label executes statements on normal exit from the loop, if any
for ...{ when (...); when (...); }after{ default: 1:
2: }
$my_very_long_identifier=$first_var.$second_var if length($second-var)>0;
Also in the following expression the first line has a balance of brackets and looks syntactically correct. And the second line after insertion semicolon is also syntactically correct -- it just does not make any sense.
$a = $b + $c + $d + $e;Of cause you can always use extra parentheses that will be eliminated by the parser as redundant:
$a =($b + $c ;
So when you are limited to lexical analyzer for the implementation of this feature, you need to take some compromises in the implementation which catch most of such errors but inevitably introduced a new one for somewhat "pathological" formatting styles (the firs example does not requires suffix if clause and should probably be written as
if( length($second-var)>0 ){ $my_ery_long_identifier=$first_var.$second_varAs this is defined as debugging iad we probably do not need to use #\ to inform the scanner about his choice. People who want to use it will adapt to limitation, if they benefit from this diagnostics and correction. There is no free lunch. This approach requires specific discipline to formatting your code.
No, it remains an essential tool for elite system administrators, the best second language after BASH unless you learned Python in college
There are a lot well-meaning and not so well meaning pundits who claim that Perl is dying. But after language became widespread and complier/interpreter is still supported and is included into all major OSes, it can only fade but never die. Just look at the Fortran. Also for Unix sysadmin it remains the best scripting language to use. The language which is more deeply imbedded and congruent to the Unix environment than any alternatives. After all, Larry Wall part of his career was a Unix sysadmin. Major players on early Perl development such as
One important rule about Perl is "do not be a beta addict". Generally only version included in major Linux distributions can be considered stable enough for production use. RHEL 7 uses Perl 5.16.3, so this version is the upper bound for production scripts right now.
As Perl development funds are scarce and it takes years to polish a particular release. That's why now it usually happens only with releases included in major Linux distribution, which has reposes to do additional testing and bug fixing. While Perl development are working as hard as they can, the problem of insufficient manpower can't be ignored.
Let's assume that the current version is 5.30.1. That means that version 5.26.3 (previous version which was used in Cygwin, which is usually far ahead in Perl version then Linux distributions) will work more reliably. And version 5.16.3 used in RHEL 7 is recommended for production code.
As for Python popularity it is connected with the power of modern computers. On computers typical for say 1996 Python did not stand a chance. The level of overhead Python impose on programmer is substantial. Just watch Advanced Python or Understanding Python - YouTube. This is pretty realistic assessment of the complexity of the Python (and by extension inefficiency of its implementation). All this public masturbation with multiple inheritance and other esoteric concepts are so far from problems any sysadmin needs to solve that you probably should stay clear of this language created during the period of over fascination with OO. You better try to learn Golang instead, as, at least, it is faster then Python ten times or more :-). Golang deliberately omits certain OO fads which dramatically increase overhead, including inheritance and generic programming: two favorite topics of language complexity junkies.
Thanks God Perl did not fully dived into OO complexity mess due to lack of resource on the language development. Still the number of complexity junking of Perl forums is really excessive. To the extent OO is useful all the features of it are available in Perl (separation of namespaces, multiple entry procedures, initialization via constructors are the most important) Using any class that has only one instance is just a modern perversion.
So in no way Perl is dying, but what is true there is a lot of unjustified hostility for the language. Which mostly comes from people who never learned the language to any significant depth, but who like to demonstrate their prejudices. It gretly hurt the lange. As well as rapid development of competitors such as PHP, Python, Javascript, Ruby, R to name just a few. Like in many other spheres the winner is often not the best language, not the most powerful and flexible. But which is currently is the most politically correct. With OO-paradigm being as popular as it is it became Python. There is nothing wrong with Pythons and it is nice language, but it is not as fun to program as in Perl. It tries to enforce its own idiosyncratic "pythonic" view on the worlds and to the extend that it deviates from Unix and C-tradition it is bad. In addition from a simple language suitable for beginners courses at universities it developed into a monster that rival complexity of PErl (and in some areas exceed it). and due to abuse of OO tend to create programs that are way too slow.
In a way that reminds me a sad history of PL/1 which was also the language which was far ahead of the baseline in late 60th (this is the language which introduced exceptions, classic string functions (substr, index, translate), pointers, genetic procedures, macrogenerator as the first path of compilation (inherited by C), classic classes of variables (static, automatic and controlled) as well as two visibility classes (local and external), and the dynamic storage allocation into mainstream (along with quality debugging and optimizing compilers, real masterpieces of software engineering) and which served as an inspiration for C)
Similar Perl introduced several lexical innovations such as many new digrams, prefix tags for strings (q, qq. qr, qx), postfix conditionals, handing namespaces as via special statement, access to internal structures of the interpreter, amazing debugger, and some operations on arrays which remind me of SETL.
All-in-all Perl remains an elegant scripting language which is fun to program in.
Perl has an interesting historical path: from a language for elite system administrators to mass Web development language and back to the tool for elite system administrators. Several (or may be most) early adopters of Perl such as Randal L. Schwartz and Tom Christiansen (author of Csh Programming Considered Harmful, 1995 ) were outstanding Unix system administrators.
Perl has an interesting historical path: from a language for elite system administrators to mass Web development language, and back to the tool for the elite system administrators |
Perl is here to stay at least for the community of elite Unix sysadmin (which is a large community and it is the community in which Perl started), because it is a natural fit. It was created by a sysadmin and carry a lot of commonality with classic Unix tool set. And first of all with Unix shell, which is the language which all sysadmin known and use. In this respect it beats Python and Ruby hands down. Both Python and Ruby also carry too heavy OO baggage and that's also diminishes their value as sysadmin tools -- only few tasks in system administration area can benefit from OO approach. You can appreciate Perl more (and also see Python more realistically despite all hype) if you try to write a couple of utilities for sysadmin work in Python. Then you would instantly understand how fake are cries about Python superiority over Perl. At least in this particular domain. Languages are really similar in power, but Perl 5 is much more convenient to use despite worse type system, necessity to put semicolons at the end of statements and other annoyances.
Another thing that you will understand is that the popular claim that Python is orthogonal and Perl is baroque language is not quite true. Python pushed a lot of complexity into modules/libraries (which are extremely baroque and some of them badly architectured) and that backfired. It also discard several typical for people who program in C constructs (no C-style for loop; no ++ and -- for no obvious reason.) That reminds me idiotism of some language construction decisions in Pascal which has for loop with increments only by one ;-)
And several popular construct of Perl are not very well emulated in Python. We can start with the pointers and the concept of "undef" :-) . Neither language can be mastered in full by mere mortals due to the level of complexity they achived: you always use some subset and need to consult documentation each time you use some rarely used part of the language. and re-learn it again and again. And Python related OO-hype is what it is -- hype -- OO does not help much in writing system programs. Modules and explicit control over namespaces are two things that usually all you need and want.
Now the idea of Perl 6 mutated is the separate language (Roku) and that's good. One can see that in Perl 6 OO zealots prevail over more cooler heads and it try to use paradigm used in Python and Ruby competing with them in the same space. Looks like Larry Wall bough OO hype "hook, line and sinker", and that was a questionable decision, making Perl 6 "Jonny come lately" in this category.
There were several much simpler areas were Perl 5 could be more profitably be extended such as exceptions, coroutines and, especially, introducing types of variables (forced conversion based on operator used (borrowed from Unix shell) is probably one on the most serious problems with Perl 5, and it inferior even to questionable "lazy typing" used n Python, when a variable carries its type after the initial assignment (but Python fall into other extreme -- it prohibited automatic conversion even in cases when it is relatively safe.) Actually history static types proved to be better that iether "wild west" typing or lazy typing and that's what should be used new languages and added to the old one (GO has static types and now eats Python lunch rising to the top three in GitHub).
Now a couple works about OO (not as a religious doctrine, but as a way to structure the program namespaces). I think modules can do 80% of that is useful in OO programming (managing namespaces) with only 10% of added complexity. Moreover, OO does not matter much for writing system utilities, because in this case (unlike say GUI where windows fall pretty neatly into OO paradigm) there no useful application of the concept of a class (function prototype, or structure with several references to subroutines along with data fields) with multiple instances. It is also sad that Larry Wall also did not realize that Javascript prototypes based OO model is a much better implementation of OO than Simula-67 model.
In any case Perl 5 modules do 80% of what is useful in classes (namely provide a separate namespace and the ability to share variables in this namespace between several subroutines) without any OO. If you wish, a primitive constructor that initializes variables (for example state variables) can be implemented as a BEGIN block. And for a medium to large programs the control of the namespace is what matters most.
The synergy with Unix shell and access to Unix API alone makes Perl preferable language for writing small utilities which can help of automate sysadmin tasks -- the main use of any scripting language for sysadmins. As it partially was created as an attempt to merge shell and AWK on a new level it has strong conceptual linkage to bash. It is , essentially, a Borne shell that would be created if Stephen_R._Bourne was replaced by the developers of AWK ;-)
As of 2019 Perl remains one of the major scripting languages and has probably the second largest amount of production code running of any scripting language, although most of it was written a while ago. It is not that visible on GitHub, but you understand that GitHub store way too many vanity and dead projects, so total number of projects using particular language does not tell you a lot. Amatures generally do not count. Let' assume that only projects with 100 or more stars matter. For example Bugzilla (over 300 stars). Outside system administration (, few large system development projects now use Perl ( bioperl.org was probably the last large project of this type and it is gradually is replaced by biopython). In the past several large Web sites such as Yahoo and Amazon used Perl as the programming language.
Perl no longer is used much for Web development, but the level of suitability to sysadmin tasks was and remain unsurpassed. Because Python is used in Universities for teaching programming it became more popular for sysadmin tasks as well, but Perl in this niche still is superior to any viable alternative including Python. So Python ascendance was not only due to the quality of the language and its implementation, but also due to so called "Peter Naur effect": Peter Naur (of Algol 60 report and BNF notation fame) in his 1975 lecture "Programming languages, natural languages, and mathematics" which later was reprinted in hypothesized that since late 70th only those future languages what can be thought to beginners have changes to enter the "main" programming languages space. All others are limited to niche applications. In this sense Perl is a clear violation of Peter Naur hypothesis ;-).
Anther important factor in Perl success is that Perl is a very interesting language with highly unorthodox design, which despite its warts produced a lot of innovative, even for this day concepts. As such it is attractive to elite programmers and system administrators who can master the language complexity and benefit form its expressiveness. For example it is one of the few scripting languages which has concept of pointers as a data type, much like C. Also it is unique in a sense that has explicit directives (package) for managing namespace. Not to say an excellent access to Unix internals (Larry Wall was a "superstar" Unix system administrator and it shows)
Perl also has several very well written textbooks although latest popular O'Reilly books are mostly junk as they were captured clueless OO advocates (see Perl for system admins for extended discussion). Perl pioneered huge testing suit for the language and is very stable. Versions 5.8.8 used in older Linux version (like RHEL 5) and version 5.10 that is used on many current Linux distributions are very stable indeed. Version 5.10 is preferable as it introduced several new features useful for sysadmin tasks and first of all state variables -- variable that can be declared in subroutines but which behave like static variable and are not reinitialized on entry to the subroutine. Also strict mode helps to cope with the problem of contextual declaration of variables, which the source of nasty and difficult to find errors as misspelled variables are viewed as just another variable with the default initial value.
Perl script can be writing in a way when they are transparent, readable and manageable. No less so then Python scripts which typically suffer from the abuse of OO. The pervert trend of some Perl guru to push to the limit expressiveness of Perl and used difficult to comprehend idioms should be resisted. Actually if you look at Larry Wall early scripts in Perl 4 he also abused this capability of the language, but he can be excused as a designed of the language. But people like Randal L. Schwartz who make the abuse of language expressiveness a semi-legitimate "Perl Guru" style which gave Perl a bad name should be condemned and never followed. Here I am reminded Talleyrand advice to young diplomats "First and foremost not too much zeal".
This is a very limited effort to help Unix sysadmins to learn of Perl. It is based on my FDU lectures to CS students. See also my ebook Introduction to Perl for Unix system administrators It discuss an approach to programming known as "defensive programming" and limits exposure of Perl to a subset of Perl which can be called "Minimal Perl". Which is only logical as this site explicitly condemns and tries to counter "excessive complexity" drive that dominates many Perl-related sites and publications.
For sysadmins Perl hits a "sweet spot": (a) it is available on for all Linux distributions (it is important as often in large corporate environment installation of additional languages is prohibited by the security department); (b) it integrates very well (I would say amazingly well) in the shell environment; (c) it easily replaces multiple utilities (sed, awk, bash for longer scripts, etc.) and is uniform between different flavors of Unix solution; (d) there are modules to interact with the entire application stack including databases.
One important advantage of Perl over Python is that is very close to shell and programming skills for shell can be reused in Perl; no so much in Python which stems from European school of language and compliers represented by Nicklaus Wirth. Also Perl also significantly faster then Python, which carry the burden of object orientation even to single variables (creating for each of them something like inode) although on modern CPUs and for the tasks of writing utilities this is critical only for a few tasks (log processing tasks is one example).
And if one think that Python is a "regular language" I can tell you that it is not. For example variables in Python are treated in C/Perl style -- assignment creates a copy of the variable.
a=3 b=a a=5 # at this point b is still equal 3, like in Perl
But for arrays and other "compound objects" this is not the case:
alist = [25,50,75,100] blist = alist # here Python copes the reference, not the array. so any change of alist[0] actually changes blist[0] too
The same is true about overall complexity of the language. The complexity of Python was just pushed into modules, it did not disappeared. And for example for string processing Python is more complex and less expressive language then Perl in which most text processing is done via regex engine. For example, Python does not have anything close in convenience to double quoted literals with interpolation until Python 3.6. Only in Python 3.6+ you have something similar with f-strings:
#!/bin/env python3 job = 'foo' cpus = 3 print(f"job {job}") print(f"cpus {cpus}")
Equivalents of Perl double quotes strings changed in Python half-dozen times, arriving to the close analog only in version 3.8. In older versions of Python you need to use Fortran format style strings with % macros. And the best way to imitate Perl/shell double quoted string changes with each major version of Python (String interpolation - Wikipedia), which tell you something about consistency:
# in all versions apples = 4 print("I have %d fruits" % apples) # implementation via % operator; no longer recommended print("I have %(apples)d fruits" % apples ) # name of the variable is allowed; no longer recommended # with Python 2.6+ print("I have {0} fruits".format(apples)) # do now this is a method print("I have {a} fruits".format(a=apples)) # names instead of positional numerics # with Python 2.7+ print("I have {} fruits".format(apples)) # positional value now can be omitted
# with Python 3.0+
from string import Template s = Template('I have $frutno fruits') # The template object s.substitute(frutno=apples) # actual substitution # or with Python 3.6+ print(f"I have {apples} apples") # radically new implementation based on f-string
If you want interpolation in HERE strings in Perl you do not need to do anything special -- its automatic. But with Python only version 3.6+ has some analog called triple-quoted f-string:
cpus = 3 job = 'foo' print(f'''\ job {job} cpus {cpus}''')
And if you you think that Python is logical original language superior to Perl I have a Brooklyn bridge to sell to you. For example in Python search of the string can be performed with find method (C programmers and Perl users be damned):
message = "hello world" pos = message.find("lo") print(pos)
If the substring is not present, find returns a value of -1 like index function in Perl. But the find() method should be used only if you need to know the position of the substring. To check if substring is present in the string in conditional expression you need to use the in operator. And there is also index function in Python that behave differently, just to make C -programmers crazy ;-) It throws exception if the substring is not found. This incompatibility suggests that Python designers have very little knowledge/respect of Unix and C when they started their project.
Moreover, if one wants to to calculate the length of the string in Python, he/she needs to use len function, not length method as one would expect.
message = "hello world" mlen = len(message)
And such "non-uniformities" and special cases are all over Python language. Also the mere number of methods provided in for each type is overwhelming in Python. For example there are 37 (thirty seven) string methods. Perl has just a dozen string functions. Everything else is done via regular expression. Strings in Python are immutable which create performance penalty.
While there are some reason to criticize Perl of excessive fascination with digrams and trigrams, Perl like an icebreaker opened for newer languages interesting avenues in the lexical structure of the language. For example, IMHO, it is is under influence of Perl Python got such lexical elements as r, b and f strings as well and triple quoted strings.
I think that this level of understanding of Perl is typical for "level-zero" comparisons done by level-zero programmers ;-). As soon as an article claims that Perl is less readable that Python (or other language) this is telling indication that the article is junk and the author does not understand what he is writing about. Or more charitably it reflects superficial problems with the language typical for novices, who are limited to "toy" programs. Other features of the language are in play as for readability of medium and large programs.
For example, in the article Dive Deep Into Python Vs Perl Debate - What Should I Learn Python or Perl (there is nothing deep in this article; it is extremely superficial) the author claims:
Perl has a very complex code which makes it difficult to understand for a novice. Subroutines, and even other symbols like:
‘$`’
,‘$&’
etc are hard to understand and program for a less experienced programmer. Also, Perl code when read would be difficult and complex to understand unless you have a quality experience.
In reality, sigils like "$" do not badly affect readability in most cases, and can even add to it. For example, this solution automatically prevents using variable names identical to reserved keywords or names of built-in functions, which is problem that Python programmers, especially those who have experience with other languages, need to deal with.
The real readability issues for medium and large size programs revolve around the concepts of lifespan, visibility of variables and handling of namespaces. They are not limited or even greatly influenced by the lexical level. The idea of namespaces is the generalization of the concept of global and local variables on a new, revolutionary level qhch makes access to them similar to the access of files in Unix. They were introduced along with the concept of Modules in Nodule -- the language developed by Nicklaus Wirth in the mid-1970s, It was quickly discontinued and replaces with Modula-2 developed between 1977 and 1985 which achieves some level of popularity in system programming and survived to this day.
The most important issue that defines readability is the rules for visibility of the variables. This is the area were Python beats Perl, as in Python global variables are visible within subroutines but can't be changed without using global keyword to define them. This is pretty ingenious, elegant solution for a very difficult and important problem. In Perl global variables are not only visible in subroutines, but can't be changes in them. Attempt to change them creates a local variable with the same name (which might be not what programmer intended, and as no warning were given by interpreter, this is a double edge sword which might introduce subtle errors in the program)
Moreover in Perl is you assign a value of variable not declared as my in a subroutine to the variable that variable enters the global scope. Which often is undesirable. And for one letter variables often used for indexes such as $i, $j, $k, $l, $m invites troubles.
In Python all variables the value to which is first assigned within the subroutine are automatically assumed to be local. That eliminates the need to my keyword, which in Perl compensates excessive visibility global variables.
The second issue is the ability to specify the lifespan of the variables. Typically local variables are what PL/1 (which is the language which originated many concepts used in later languages) were called "automatic" variables and Perl calls my variable: the storage for them is allocated at the entry to the subroutine and is destroyed at the exit (they are sometimes called stack variables). The other type of variable often called external in PL/1 (but that has nothing to do with visibility) are allocated at the beginning of execution of the script and exists for the whole direction of program. Their visibility can be local or global. so visibility is assigned independently of lifespan. In PL/1 they are called static as storage for them was allocated during compilation and included into object file and in case they are global they are called external. Now all variables are allocated on the heap, so the word "static" is incorrect but still reflects the essence.
In this area Perl has what Python is lacking and what greatly help structuring and understanding of large programs: local variables with the lifespan of global variables (which preserve their value from one invocation to another). Thos variables called state help to lessen the number of interactions between subroutines, in a way which in Python requires usage of classes. And this feature of Python stimulates the abuse of OO for tasks that does not fit this paradigm, which negatively affects readability and increase the number of lines of code.
The third important issue is namespaces. which becomes the dominant issue in readability as program size increases (say, above, 10K lines.) For a large program it is absolutely essential to partition namespace into separate sub-namespaces and specify the rules of visibility for those variables. This is called exporting of the variable.
As for namespaces Perl is more flexible then Python -- in Python namespace are replica of Module namespaces and are firmly associated with the module ("one module --one namespace). In Perl you can define additional namespaces when you need them within the same modules, using the "package" keyword. Both languages allow to access variables from a different namespaces by qualification them with the the name of the namespace -- a similar mechanism that is used in Unix for accessing files, when you need to specify path, when you are accessing a file from a different directory. Here Perl is more flexible then Python because in Perl you can also specify set of variables visible externally in the module, but you can import only a fraction of them in each of other modules from this namespace.
The other approach is use of subclasses in OO, but this is another story and this approach has certain advantages and drawbacks and is less important in comparison with the revolutionary concept of the module introduced by Wirth in Module language. The critical part of success of OO success is not object orientation (which is an obscure and questionable concept, outside few application domains) but the implementation of hierarchical namespaces model, in which siblings has access to parent namespace.
Despite the slide in popularity Perl experienced since 2000 Perl and severe lack of resources for the development of the language, Perl continues to evolve and improve. Thankfully it evolves slowly, but during the last decade we got state variables (5.10) and a couple of other useful features. Along with several useless features or features that which many would consider redundant or even harmful and that should probably be removed from the language. The latter is due to the fact that after the create of the language steps down there is no high authority to "bless" changes for conceptual integrity. And petty people with high opinion about themselves and pretentions to become high priests of the community try to make their "scratch" by spoiling the language :-(. This is a common, well known problem with large open source project is which original developer stepped down and it is not limited to Perl. It is often described under the title "the loss of conceptual integrity" *the term introduced in the The Mythical Man Month by Fred Brooks. Different manifestation of the same are also known Software Peter principle , Software entropy and Featuritis
So far the evolution of Perl failed to resolve the most obvious problem with the language such as
Contrary to popular opinion the use of sigils in Perl is more or less logical especially for scalar variables. Sigil $ denotes derefercing. It is also undeniable that string interpolation inside double quoted string is easier with sigils. Moreover sigils also clearly demarcate variables from built-in functions and subroutines making wting syntax coloring in editors easier. So this particular decision withstand the test of the time.
Contrary to popular opinion, syntax of Perl 5 is pretty regular, and closely adheres to traditional C-style syntax which makes it easy to learn for both sysadmin coming from BASH or ksh and C or C++ programmers coming from respective language. It can favorably compared with the disaster which is syntax of Borne shell.
Actually it does not look too bad in comparison with Python which has syntax rules which are much farther from C and Unix. Python creates severe cognitive dissonance for people who program in C or C++. Especially with some decisions like usage of whitespace to determine the nesting. This decision has serious negative effects for long multipage loops and other control constructs, forcing to make them shorter. Not that C-style solution used in Perl is perfect (runaway unclosed '{' bracket is a huge problem with this notation), but at least it is uniform with C and C++, which is important. People who spend many years programming C or C++ have their own methods to compensate for the deficiency of this notation and accumulate tremendous skills of reading it and using it large programs. Experience that Python just sends to the dust bin.
Somehow due to his natural talent (he was never trained as a compiler writer and does not have CS degree) Larry Wall managed to avoid most classic pitfalls in creating of the syntax of the language, pitfalls in which creators on PHP readily fell ("dangling else" in PHP is one example) and from which Python suffers as well.
Just as a side note Python inherits from C usage of = for assignment and == for comparison, the blunder that has very serious consciences as for the amount of errors both in C and Perl. In Python assignment is invalid in conditional expressions (Python 3.8 introduced Walrus operator := for assignment in conditionals), which makes it safer and eliminates this type of errors, but at the same time losing expressive power and making programs more verbose:
if a=1 : print a ^ SyntaxError: invalid syntax
One of Perl’s better-kept secrets is its built-in debugger that allows developers to test their programs with ease and to rapidly track down errors in their Perl scripts. Python only recently got a semi-decent debugger. Before that the language sucked badly. PHP is another similar sicker. Actually for qualified programmer the quality of the debugger is as important if not more important then the quality of the language. In this area Perl really shines as it has powerful debugger as long as I remember (it did have it in 1994 when I started to use it)
This is a very powerful tool that unfortunately few Perl programmers (and even fewer sysadmins) know well. It allows to create debugging scripts, create you own set of aliases for each program you debug, as well as remote debugging. I view it a crown jewel of the Perl language environment.
While number of IDE that Perl has is less then Python you can use free Komodo editor (somewhat buggy and idiosyncratic, but OK) or pycharm which does not advertize its support of Perl but does it really well (and it has a free version for individual developers). Eclipse has Perl plug-in as well. all of them integrates with Perl debugger.
I think the second book about the language you should read should be a book about Perl debugger (see below)
|
While Python is not installed by default in all major Linux distributions too, this is not true for AIX, Solaris and HP-US. And in highly secure environment you are prohibited installing such huge packages without jumping via so many bureaucratic hoops that you regret that you started this adventure.
Systems administrators need to deal with many repetitive tasks in a very complex, and changing environment which often includes several different flavors of Linux (RHEL and Suse) and Unix (Solaris, HP-UX and AIX). Linux has Perl installed by default. It is also included in all major Unix flavors but version installed might be outdated and need upgrading. For example Oracle installs Perl too, so it is automatically present on all servers with Oracle database. Some other application install Perl too. That means that it provides the simplest way to automate recurring tasks on multiple platforms. Among typical tasks which sysadmin need to deal with:
You definitely can greatly simplify your life as well as improve "manageability" of the servers (or group of servers) with additional Perl scripts, some written by use, some borrowed and adapted to your environment. As long as you still apply KISS principle and do not try to overload those scripts with "features". Because at some point the task of maintaining the scripts became evident and unless scripts are simple the game might not worth the candles. that's the gotchas, which catches many sysadmin who overreached and added too much complexity to their scripts. The slogan KISS can be in this contest mean: keep it simple sysadmin.
As most sysadmins already know shell, the affinity with shell is one of the major advantages of using Perl as the second scripting language for Unix sysadmin. no other language come close in this respect: Perl allow to reuse most of the key concepts of the shell.
IMHO the main advantage of using powerful complex language like Perl is the ability to write simple programs which in the past required for sysadmin to use several languages (bash+AWK+SED). It also was created without OO which later was "bolted on". And I consider this a very important advantage for sysadmin domain of utilities. Perhaps the world has gone overboard on this object-oriented thing. I do not see much use of it for utilities space -- they add nothing and the attempt to structure utilities in OO fashion typically backfires and leads to excessive complexity and bloat. Often it leads to the creating what is called "object oriented spaghetti".
At the same time Perl is surprisingly high level language and for writing sysadmin utilities is has higher level then Python. You do not need many tricks used in lower level languages as Perl itself provides you high level primitives for the task.
This page is linked to several sub-pages in the top "contents" table. The most important among them are:
All language have quirks, and all inflict a lot of pain before one can adapt to them. Once learned the quirks become incorporated into your understanding of the language. But there is no royal way to mastering the language. The more different is one's background is, more one needs to suffer. Generally any user of a new programming language needs to suffer a lot ;-)
When mastering a new language first you face a level of "cognitive overload" until the quirks of the language become easily handled by your unconscious mind. At that point, all of the sudden the quirky interaction becomes a "standard" way of performing the task. For example, regular expression syntax seems to be a weird base for serious programs, fraught with pitfalls, a big semantic mess as a result of outgrowing its primary purpose. On the other hand, in skilled hands this is a very powerful tool that can serve a reliable parser for complex data and in certain cases as a substitute for string functions such as index and substr.
There are several notable steps in adaptation to Perl idiosyncrasies for programmers who got used to other languages:
That's easy for those people who use write their own shell scripts and generally is not a problem for sysadmins. Most mistakes
when you omit $ in front of the variable are diagnosed by interpreter, but some cases like $location{city} are not. The
problems arise if along with Unix shell you use the third language, for example C. In this case you automatically makes
make mistakes, despite your experience, and you need conscious effort to avoid them all the time. This is the case with me.
Especially if you use other language in parallel with Perl. In this case such errors crop into your scripts automatically.
Only if one of the operators of "==" is a string constant, meaningful automatic diagnostic can be provided.
I would way that the lack of build-in Prettyprinter in Perl is a blunder of the designers of Perl interpreter. It is understandable
as Perl never enjoyed sizable material support from big corporations, but still...
Please note that as syntax of Perl is complex. So the diagnostic in Perl interpreter is really bad and often point to the spot far below where the error occurred. It is nowhere near the quality of diagnostics that mainframe programmers got in IBM PL/1 diagnostic complier, which is also probably 50 years old and run on tiny by today standard machines with 256K (kilobytes, not megabytes) of RAM and 7M (megabytes, not gigabytes, or terabytes) harddrives. The only comfort is that other scripting languages are even worse then Perl ;-).
All-in-all Perl is the language that fits most sysadmin needs, It' not fancy and its general usage is in decline since 2000 but fashion should never be primary factor in choosing the scripting language. Perl has stable and well tested interpreter and is close to shell (to the extent that most concepts of shell can be directly reused). And that's what important. As on modern servers Perl interpreter loads in a fraction of a second, Perl also allows to get rid of most usage of AWK and SED, making you environment more uniform and less complex. This is an important advantage. Among benefits that Perl bring to system administration are
In short if make sense to learn Perl as it makes sysadmin like a lot easier. Probably more so then any other tool in sysadmin arsenal...
Perl is really great for text processing and in this particular domain is probably unmatched. For example in Python regular expressions are implemented via standard library module; they are not even a part of the language.
As of 2017 Perl no longer belongs to the top 10 programming languages (Scripting languages slip in popularity, except JavaScript and Python, Infoworld, Nov 13, 2017). It's still more popular then Visual Basic, so there nothing to worry about. But far less then popular then Python. Of cause popularity is not everything. Python and Perl share some characteristics, but don't exactly occupy the same niches. But it is a lot: fashion rules the programming, so this is a factor that you need consciously evaluate and be aware of.
In large enterprise environment, outside system administration area Perl now is almost invisible. Python is gaining ground in research. Mostly because universities both in the USA and Europe now teach Python in introductory classes and engineers come "knowing some Python". This looks like "Java success story" of late 1990th on new level. Like Perl, Python is also now installed on all Linux distributions by default and there are several important linux system programs written in Python (yum, Anaconda, etc) which implicitly suggest that Python has Red Hat mark of adoption/approval too (yum was originally written at Duke University Department of Physics)
So there is now a pressure to adopt Python. That's sad, because IMHO Perl is a great scripting language which can be used on many different levels, starting from AWK/SED replacement tool (this especially make sence if you use different platforms. for example their behavior differs between Mac OS X and Linux. But PERL is the same in both those environments.). Going from Perl to Python for text processing to me feels like leaving a Corvette and driving a station wagon. Python will gets you there. But it's not fun and will take more time although you probably might feel more comfortable inside.
Here is an insightful post on this topic (Which is better, Perl or Python Which one is more robust How do they compare with each other):
Joe Pepersack, Just Another Perl Hacker Answered May 30 2015Perl is better. Perl has almost no constraints. It's philosophy is that there is more than one way to do it (TIMTOWTDI, pronounced Tim Toady). Python artificially restricts what you can do as a programmer. It's philosophy is that there should be one way to do it. If you don't agree with Guido's way of doing it, you're sh*t out of luck.
Basically, Python is Perl with training wheels. Training wheels are a great thing for a beginner, but eventually you should outgrow them. Yes, riding without training wheels is less safe. You can wreck and make a bloody mess of yourself. But you can also do things that you can't do if you have training wheels. You can go faster and do interesting and useful tricks that aren't possible otherwise. Perl gives you great power, but with great power comes great responsibility.
A big thing that Pythonistas tout as their superiority is that Python forces you to write clean code. That's true, it does... at the point of a gun, sometimes at the detriment of simplicity or brevity. Perl merely gives you the tools to write clean code (perltidy, perlcritic, use strict, /x option for commenting regexes) and gently encourages you to use them.
Perl gives you more than enough rope to hang yourself (and not just rope, Perl gives you bungee cords, wire, chain, string, and just about any other thing you can possibly hang yourself with). This can be a problem. Python was a reaction to this, and their idea of "solving" the problem was to only give you one piece of rope and make it so short you can't possibly hurt yourself with it. If you want to tie a bungee cord around your waist and jump off a bridge, Python says "no way, bungee cords aren't allowed". Perl says "Here you go, hope you know what you are doing... and by the way here are some things that you can optionally use if you want to be safer"
Some clear advantage of Perl:
Advantages of Python
- Moose: postmodern object system for Perl. Declarative programming FTW.
- One liners. Perl has a whole set of shortcuts for making it easy to write ad-hoc scripts on the command line
- Speed. For most tasks, Perl is significantly faster than Python
- Regular expressions are a first-class datatype rather than an add in. This means you can manipulate them programatically like any other first-class object.
- Power. You can do things in Perl that are either much harder, or prohibited, in Python. For instance the <> operator... this lets you trivially deal with the complexities of opening files from the command line and/or accepting streams from pipes or redirection. You have to write several lines of boilerplate Python code to duplicate the behavior of Perl's
while (<>) { ... }
construct (or even more trivially the -n switch, which automatically wraps your code with this construct).- No significant whitespace. If your formatting gets mangled (by, say, posting it to a web forum or sending it in an email that munges whitespace), the meaning of your code doesn't change, and you can trivially re-format your code with Perltidy according to whatever coding style you define. You can format your code as to what is most clear in context, rather than having to conform to an arbitrary set of restrictions.
- Postfix notation. This can be ugly and is easily misused, but used with care it makes your code easier to read, especially for things like
die if $condition
ordie unless $condition
assertions.- Sigils. It's a love it or hate it thing, but sigils unambiguously distinguish variables from commands, make interpolation effortless, and make it easy to tell at a glance what kind of variable it is without having to resort to some ugly hack like Hungarian notation.
- Inline::C and all of the other Inline::* modules). Yes, you can write Python extensions in C but Inline::C makes it effortless.
- Pod is vastly more powerful than Docstrings, especially when you throw in the power of something like Pod::Weaver to write/manipulate your documentation programmatically.
- JVM interoperatiblity. For me this is huge. It's the only thing that Python does better than Perl. Being able to write code that runs in the JVM and to work with Java objects/APIs without having to write Java code is a huge win, and is pretty much the only reason I ever write anything in Python.
- Learning curve. Python is easier to learn, no denying it. That's why I'm teaching it to my 12 year old son as his first programming language
- User community. Python is more popular and has a larger active user community. Appeal to popularity is a fallacy, but you can't just dismiss mindshare and 3rd party support either.
Usage of IDE is a must in the current environment. Often sysdmins neglect this, but it does diminished their productivity. the key here is a powerful editor, built-in remote debugger while nice is not absolutely necessary. But ability to compare two versions, show usage of particular variable and prompt for the write variable when writing statements are important. Show of nesting and pretty printing are also important but can be done with the external tools. Also important is the ability to work with data-space (renaming varibale in files for the whole project, etc). Perl does not even ship with the "Standard IDE". But there are several usable options:
My feeling is that for Perl to remain competitive IDE should be maintained and shipped along with Perl interpreter (like in Python and R distributions). May be at the expense of some esoteric modules included in standard library.
Python now dominate books on scripting languages and number of books per year devoted to Python and available via Amazon for 2017 is at least one order of magnitude larger then the number of books devoted to Perl (quality issues aside). All this creates a real pressure to use Python everywhere, even in system administration. But first of all very few Python books are good. Most do not explain the language well. And the second is that you need just a couple of them not a dozen. So while on number front Perl definitely can't compete with Python several quality books (most not from O'Reilly) are available. i would recommend (Recommended Perl Books)
RHEL 6.x now ships with Perl 5.10. Many classic Unixes still ship with Perl 5.8.8. Older versions of Solaris and HP-US servers might have version below Perl 5.8.8 but in 2017 that's rare as most of such servers are decommissioned (typical lifespan of a server in corporate environment is 5-7 years).
It you need compatibility with all major flavor of Unix in you scripts it is a safe bet to write for Perl 5.8.8. Such a decision virtually guarantee compatibility with all enterprise servers, except those that should be discarded 5 or 10 years ago. In other words no "state" variables, if you want "perfect" compatibility. Non perfect, but acceptable.
If you need only Linux deployment compatibility that can be achieved by using version 5.10 which allow you to use "state" variables.
If you need compatibility with linux servers only version 5.10 look like a more or less safe bet too (very few enterprise servers in 2017 are now below version RHEL 6; those typically have Perl 5.8).
Also too high version of Perl 5 is actually not desirable -- see note about Perl 5.22. (the current version of Perl 5 is version 30). Hopefully warts added to version 22 will be corrected based on the feedback. Here is a slide from Oct 3, 2016 by Tom Radcliffe The Perl Paradox
There is a type of Perl books authors that enjoy the fact that Perl is complex non-orthogonal language and like to drive this notion to the extreme. I would call them complexity junkies. Be skeptical and do not take recommendations of Perl advocates like Randal L. Schwartz or Tom Christiansen for granted :-) Fancy idioms are very bad for novices. Please remember about KISS principle and try to write simple Perl scripts without complex regular expressions and/or fancy idioms. Some Perl gurus pathological preoccupation with idioms is definitely not healthy and is part of the problem, not a part of the solution...
We can defines three main types of Perl complexity junkies:
My issues with Perl is when people get Overly Obfuscated with their code, |
Please remember about KISS principle and try to write simple Perl scripts without overly complex regular expressions or fancy idioms. If you do this Perl is great language, unmatched for sysadmin domain. Simplicity has great merits even if goes again current fancy.
Generally the problems with OO mentioned above are more fundamental than the trivial "abstraction is the enemy of convenience". It is more like that badly chosen notational abstraction at one level can lead to an inhibition of innovative notational abstraction on others. In general OO is similar to idea of "compiler-copiler" when you create a new language in such a way that it allow to compile new constructs with the existing complier. While in some cases useful or even indispensible, there is always a price to pay for such fancy staff.
Some deficiencies of Perl syntax were directly inherited from C. One of the most notable "obligatory semi-colon after ach statement. Which lead to tremendous amount of errors. You can use "soft semicolon" approach (implied semicolon on line end if round brackets or similar symmetrical symbols are balanced) and put semicol on each line and then depete it on a fewline that do not need it
It is eady to implement using any editor maro (for example in vi) or as a mode of the pretty printer.
Such an approach cuts number of iteration required to get rid of syntax errors by two or three.
One of most famous C design blunder was the introduction of a small lexical difference between assignment and comparison (remember that Algol used := for assignment; PL/1 uses = for both) caused by the design decision to make the language more compact (terminals at this type were not very reliable and number of symbols typed matter greatly. In C assignment is allowed in if statement but no attempts were made to make language more failsafe by avoiding possibility of mixing up "=" and "==". In C syntax if ($a = $b) assigns the contents of $b to a and executes the code following if b not equal to 0. It is easy to mix thing and write if ($a = $b ) instead of (if ($a == $b) which is a pretty nasty bug. You can often reverse the sequence and put constant first like in
if ( 1==$i ) ...
as
if ( 1=$i ) ...
does not make any sense, such a blunder will be detected on syntax level.
This is the problem with all C-style language not only Perl. Ruby managed to avoid it switching to Algol-style delimiters, Typically this is connected with your recent changes so you should know where to look. Pretty printer (even simplistic Neatperl) allows instantly detent this type of errors
If you do not access to any pretty-printer (a very sad situation indeed) use diff with the last version that complied OK (I hope you use come kind of CMS like subversion or git)
The optimal way to spot missing '}' is to use pretty printer. In the absence of pretty printer you can insert '}' in binary search fashion until you find the spot where it is missing. |
You can also extract part of your script and analyze it separately, deleting "balanced" parts one by one. This error actually discourages writing very long "monolithic" Perl scripts so the is a silver lining in each dark cloud.
You can also use pseudo comments that signify nesting level zero and check those points with special program or by writing an editor macro. One also can mark closing brackets with the name of construct it is closing
if (... ) { } # if
Use a good editor. moreover often you can split long literals into one line literals and concatenate them with dot operator. Perl process those at complite time so there is not run-time hit for using this (and it should not be for any other language with a decent complier -- this complier optimization is classed constant folding and is a standard in modern compliers).
As a historical note specifying max length of literals is an effecting way of catching missing quote that was implemented in PL/1 compilers. You can also have an option to limit literal to a single line. In general multi-line literals should have different lexical markers (like "here" construct in shell). Perl provides the opportunity to use concatenation operator for splitting literals into multiple line, which are "merged" at compile time, so there is no performance penalty for this constructs. But there is no limit on the number of lines string literal can occupy so this does not help much. If such limit can be communicated via pragma statement at compile type in a particular fragment of text this is an effective way to avoid the problem. Usually only few places in program use multiline literals, if any. Editors that use coloring help to detect unclosed literal problem but there are cases when they are useless.
If you are comparing a variable and a constant Perl interpret can help you to detect this error. but if you are comparing two variable you are on your own. And I often use wrong comparison operator just out of inertia or after usage of C. the most typical for ma error is to use == for stings comparison.
One way is to comment sting comparisons and then match comments with the comparison operator used using simple macro in editor (you should use programmable editor, and vim is programmable)
Usage of different set of comparison operator for number and string comparison is probably the blunder in Perl design (which Python actually avoided) and was inherited from shell. Programmer that use other languages along with Perl are in huge disadvantage her as other language experience force them to make the same errors again and again. Even shell solution (using different enclosing brackets); it might well be that in Perl usage of ( ) for arithmetic comparison and ((...)) for string would be a better deal. They still can be used as a part of defensive programming so that you can spot inconsistencies easier
Perl + C and, especially Perl+Unix+shell represent a new programming paradigm in which the OS became a part of
your programming toolkit and which is much more productive for large class of programs that OO-style development (OO-cult
;-). It became especially convenient in virtual machine environment when application typically "owns" the machine. In this case the
level of integration of the language and operating system became of paramount importance and Perl excels in this respect. You can use
shell for file manipulation and pipelines, Perl for high-level data structure manipulation and C when Perl is insufficient or too slow.
The latter question for complex programs is non-trivial and correct detection of bottlenecks needs careful measurements; generally Perl
is fast enough for most system programs.
Exploiting high level of integration of Perl with shell and Linux is a new programming paradigm which became especially convenient in virtual machine environment when application typically "owns" the machine. In this case the level of integration of the language and operating system became of paramount importance and Perl excels in this respect. In a way it is similar to LAMP paradigm. |
The key idea here is that any sufficiently flexible and programmable environment - and Perl is such an environment -- gradually begins to take on characteristics of both language and operating system as it grows. See Stevey's Blog Rants Get Famous By Not Programming for more about this effect.
Any sufficiently flexible and programmable environment - and Perl is such an environment -- gradually begins to take on characteristics of both language and operating system as it grows. |
Unix shell can actually provide a good "in the large" framework of complex programming system serving as a glue for the components.
From the point of view of typical application-level programming Perl is very under appreciated and very little understood language. Almost nobody is interested in details of interpreter, where debugger is integrated with the language really brilliantly. Also namespaces in Perl and OO constructs are very unorthodox and very interesting design.
References are Perl innovation: classic CS view is that scripting language should not contain references (OO languages operate with references but only implicitly). Role of list construct as implicit subroutine argument list is also implemented non trivially (elements are "by reference" not "by name") and against CS orthodoxy (which favors default "by name" passing of arguments). There are many other unique things about design of Perl. All-in-all for a professional like me, who used to write compilers, Perl is one of the few relatively "new" languages that is not boring :-).
The quality of the debugger for the language is as important as the quality of language itself. Perl debugger is simply great. See Debugging Perl Scripts
Perl license is a real brilliance. Incredible from my point of view feat taking into account when it was done. It provided peaceful co-existence with GPL which is no small feat ;-). Dual licensing was a neat, extremely elegant cultural hack to make Perl acceptable both to businesses and the FSF.
It's very sad that there no really good into for Perl written from the point of view of CS professional despite 100 or more books published.
A small, crocky feature that sticks out of an otherwise clean design. Something conspicuous for localized ugliness, especially a special-case exception to a general rule. ... |
Perl extended C-style syntax in innovative way. For example if statement always uses {} block, never an individual statement, also ; before } is optional. But it shares several C-style syntax shortcomings and introduced a couple of its own:
[0] # perl -v This is perl 5, version 26, subversion 1 (v5.26.1) built for i686-cygwin-threads-64int-multi (with 7 registered patches, see perl -V for more detail) ... ... ... [0] # cat lex_error.pl #!/usr/bin/perl # Error in lexical and/or syntax analysis phase of the interpreter (it does not detect ==~ as wrong operator) $a='2017'; if ( $a ==~/\d/ ){ print "String $a contains digits\n"; } else { print "String $a does not contains digits\n"; } [0] # perl lex_error.pl String 2017 does not contain digits
For a language aficionado Larry Wall make way too many blunders in the design of Perl. Which is understandable (he has no computer science background and was hacker in heart), but sad.
There are also several semantically problems with the language:
state
declares a lexically scoped variable, just likemy
. However, those variables will never be reinitialized, contrary to lexical variables that are reinitialized each time their enclosing block is entered. See Persistent Private Variables in perlsub for details.If more than one variable is listed, the list must be placed in parentheses. With a parenthesized list,
undef
can be used as a dummy placeholder. However, since initialization of state variables in list context is currently not possible this would serve no purpose.
state
variables are enabled only when theuse feature "state"
pragma is in effect, unless the keyword is written asCORE::state
. See also feature.
R-language has RStudio which probably can be viewed as gold standard of minimal features needed for scripting language GUI. While RStudio has a weak editor it has syntax highlighting and integration with debugger and as such is adequate for medium scripts.
There is no similar "established" as standard de-facto GUI shipped with Perl interpreter and looks like nobody cares. That's a bad design decision although you can use Orthodox file manager (such as Midnight commander, or in Windows Far or Total Commander) as poor man IDE. Komodo Edit is more or less OK editor for Perl and is free although in no way it is full IDE.
This is not a show stopper for system administrators as they can use screen and multiple/different terminal sessions for running scripting and editing them. Also mcedit is handy and generally adequate for small scripts. To say nothing that each sysadmin know badic set of command for vi/vim, and many know it well.
But this is a problem when you try to write Perl scripts with over 1K lines which consist of multiple files. Many things in modern IDE helps to avoid typical errors (for example identifiers can be picked up from the many by right clicking, braces are easier to match if editor provide small almost invisible vertical rulers, color of the string help to detect running string constants, etc.
Currently Komodo and free Komodo editor are almost the only viable game in town.
See
for additional discussion.
For mature language the key area of development is not questionable enhancements, but improvement of interpreter diagnostics and efforts in preventing typical errors (which at this point are known).
Perl version 5.10 was the version when two very useful enhancement to the language were added:
given($answer) { when(condition) { ... } when .... ... ... ... default { ... } }
Still very little was done to improve interpreter in order to help programmers to avoid most typical Perl errors. that means that the quality of the editor for Perl programmers is of paramount importance. I would recommend free Komodo editor. It allows you to see the list of already declared variables in the program and thus avoid classic "typo in the variable" type of errors.
Not all enhancements that Perl developers adopters after version 5.10 have practical value. Some, as requirement to use backslash in regular expressions number of iterations ( so that /\d{2}/ in "normal" Perl became /\d\{2}/ in version 5.22), are counterproductive. For that reason I do not recommend using version 5.22. You can also use pragma
use v5.12.0
to avoid stupid warnings version 5.20 generates.
There is no attempts to standardize Perl and do enhancements via orderly, negotiated by major stakeholders process. Like is done with C or Fortran (each 11 years; which is a very reasonable period which allow current fads to die ;-). At the same time quality of diagnostics of typical errors by Perl interpreter remains weak (it imporved with the introduction of strict though).
Support for a couple of useful pragma, for example, the ability to limit the length of string constants to a given length (for example 120) for certain parts of the script is absent. Ot something similar like "do not cross the line" limitation.
Local labels might help to close multiple level of nesting (the problem of missing curvy bracket is typical in al C-style languages)
1:if( $i==1 ){ if( $k==0 ){ if ($m==0 ){ # the curvy bracket below closes all opened clock since the local label 1 }:1
Multiple entry points into subroutines might help to organize namespaces.
Working with namespaces can and should be improved and rules for Perl namespaces should be much better better documented. Like pointers namespaces provide powerful facity to structuring language programs. which can be used with or without modules framework. this is a very nice and very powerful Perl feature that makes Perl a class or its own for experienced programmers. Please note that modules are not the only game in town. Actually the way they were constructed has some issues and (sometime stupid) overemphasis on OO only exacerbate those issues. Multiple entry points in procedures would be probably more useful and more efficient addition to the language. Additional that is very easy to implement. The desire to be like the rest of the pack often backfire... From SE point of view scripting language as VHL stands above OO in pecking order ;-). OO is mainly force feed for low level guys who suffer from Java...
Actually there are certain features that should probably be eliminated from Perl 5. For example use of unquoted words as indexes to hashes is definitely a language designers blunder and should be gone. String functions and array functions should be better unified. Exception mechanism should be introduced. Assignment in if statements should be somehow restricted. Assignment of constants to variables in if statement (and all conditions) should be flagged as a clear error (as in if ($a=5) ... ). I think latest version of Perl interpreter do this already.
Attention: The release contains an obvious newly introduced wart in regex tokenizer, which now requires backslash for number of repetitions part of basic regex symbols. For example in case of /\d{2}/ which you now need to write /\d\{2}/ -- pretty illogical as a curvy brace here a part of \d construct, not a separate symbol (which of course should be escaped);
Looks to me like a typical SNAFU. But the problem is wider and not limited to Perl. There is generally tendency for a gradual loss of architectural integrity after the initial author is gone and there is no strong "language standard committee" which drive the language development (like in Fortran, which issues an undated version of the standard of the language each 11 years).
So some languages like Python this is still in the future, but for many older languages is is already reality and a real danger. Mechanism for preventing this are not well understood. The same situation happens with OS like Linux (systemd).
This newly introduced bug (aka feature) also affects regexes that use opening curvy bracket as a delimiter. Which is a minor but pretty annoying "change we can believe in" ;-). I think that idiosyncrasy will prevent spread this version into production version of Linux Unix for a long, long time (say 10 years) or forever. Image the task of modification of somebody else 30-50K lines Perl scripts for those warnings that heavily uses curvy braces in regex or use \d{1,3} constructs for parsing IP addresses.
This looks more and more like an artificially created year 2000 problem for Perl.
Dr. Nikolai Bezroukov
|
Switchboard | ||||
Latest | |||||
Past week | |||||
Past month |
Jun 04, 2021 | www.perl.com
Anything after the
__DATA__
line is not part of the program but is available to the program through the specialDATA
filehandle:#!/usr/bin/perl print "---Outputting DATA\n", <DATA>, "---Done\n"; __DATA__ Dog Cat BirdThe output shows each line after
__DATA__
:---Outputting DATA Dog Cat Bird ---DoneI typically go the other way by starting with a data file and adding a program to the top of it:
#!/usr/bin/perl use v5.26; use Text::CSV_XS; my $csv = Text::CSV_XS->new; while( my $row = $csv->getline(*DATA) ) { say join ':', $row->@[3,7]; } __DATA__ ...many CSV lines...This is the end, my friend, the ENDYou probably also know that you can use
__END__
instead. I'm used to using that because it's a holdover from Perl 4 and that's where I first learned this:#!/usr/bin/perl print "---Outputting DATA\n", <DATA>, "---Done\n"; __END__ Dog Cat BirdYou get the same output:
---Outputting DATA Dog Cat Bird ---Done... ... ...
Jun 04, 2021 | www.perl.com
-x is fun
We've had fun with the
perl
interpreter and the shebang, butperl
has a-x
which is already fun by design. This option tells Perl that the program to execute is actually embedded in a larger chunk of unrelated text to ignore. Perhaps the Perl program is in the middle of an email message:"I do not know if it is what you want, but it is what you get. -- Larry Wall" #!/usr/bin/env perl print "perl -x ignores everything before shebang\n"; print <DATA>; __END__ "Fortunately, it is easier to keep an old interpreter around than an old computer. -- Larry Wall"Executing this as a program is a syntax error because the Larry Wall quote before the shebang is not valid Perl. When we execute this code with
perl -x
, everything before the shebang is ignored and it works:$ perl -x email.txt perl -x ignores everything before shebang "Fortunately, it is easier to keep an old interpreter around than an old computer. -- Larry Wall"Out of curiosity, what if we tried to go one step further? How about multiple shebangs in a file, where one of them has a
-x
:#!/usr/bin/perl -x #!/usr/bin/perlBut it only produces an error:
Can't emulate -x on #! line.There is however a trick to achieve this, by using shell
eval
. Thatperl -x
is now executed in a shell process and not interpreted by perl binary like previously.:#!/bin/sh eval 'exec perl -x $0 ${1+"$@"}' die "another day"; exit 1 #!perl print "$]\n";startperlThis article would not be complete without discussing a bit about the config variable
$Config{startperl}
. This variable comes from Config.pm that provides information about configuration environment (which you also see withperl -V
):$ perl -e 'use Config; print $Config{startperl}' #!/usr/bin/perlThis is actually built during compilation from defaults or user/vendor provided configs. What if we want a different value? Simply specify the value of this during the
./Configure
step, the configure option is-Dstartperl='...'
. We then need to rebuildperl
:$ ./Configure -des -Dstartperl='#!/my/shebang' $ make test installNow our custom value is the default:
$ perl -e 'use Config; print $Config{startperl}' #!/my/shebangExtUtils::MakeMaker and Module::Build seems also to use
startperl
among other methods to fix modules shebangs.Take care to use an interpreter or a program that behaves like a
perl
interpreter! Some CPAN modules usestartperl
to write first line of generated perl tests. The/usr/bin/env
limitation still apply here.
Jun 04, 2021 | www.perl.com
Create an anonymous temporary file
If I give
open
a filename of an explicitundef
and the read-write mode (+>
or+<
), Perl opens an anonymous temporary file:open my $fh, '+>', undef;Perl actually creates a named file and opens it, but immediately unlinks the name. No one else will be able to get to that file because no one else has the name for it. If I had used File::Temp , I might leave the temporary file there, or something else might be able to see it while I'm working with it.
Print to a stringIf my perl is compiled with PerlIO (it probably is), I can open a filehandle on a scalar variable if the filename argument is a reference to that variable.
open my $fh, '>', \ my $string;This is handy when I want to capture output for an interface that expects a filehandle:
something_that_prints( $fh );Now
$string
contains whatever was printed by the function. I can inspect it by printing it:say "I captured:\n$string";Read lines from a stringI can also read from a scalar variable by opening a filehandle on it.
open my $fh, '<', \ $string;Now I can play with the string line-by-line without messing around with regex anchors or line endings:
while( <$fh> ) { ... }I write about these sorts of filehandle-on-string tricks in Effective Perl Programming .
Make a pipelineMost Unix programmers probably already know that they can read the output from a command as the input for another command. I can do that with Perl's
open
too:use v5.10; open my $pipe, '-|', 'date'; while( <$pipe> ) { say "$_"; }This reads the output of the
date
system command and prints it. But, I can have more than one command in that pipeline. I have to abandon the three-argument form which purposely prevents this nonsense:open my $pipe, qq(cat '$0' | sort |); while( <$pipe> ) { print "$.: $_"; }This captures the text of the current program, sorts each line alphabetically and prints the output with numbered lines. I might get a Useless Use of cat Award for that program that sorts the lines of the program, but it's still a feature.
gzip on the flyIn Gzipping data directly from Perl , I showed how I could compress data on the fly by using Perl's gzip IO layer. This is handy when I have limited disk space:
open my $fh, '>:gzip', $filename or die "Could not write to $filename: $!"; while( $_ = something_interesting() ) { print { $fh } $_; }I can go the other direction as well, reading directly from compressed files when I don't have enough space to uncompress them first:
open my $fh, '<:gzip', $filename or die "Could not read from $filename: $!"; while( <$fh> ) { print; }Change STDOUTI can change the default output filehandle with
select
if I don't like standard output, but I can do that in another way. I can changeSTDOUT
for the times when the easy way isn't fun enough. David Farrell showed some of this in How to redirect and restore STDOUT .First I can say the "dupe" the standard output filehandle with the special
&
mode:use v5.10; open my $STDOLD, '>&', STDOUT;Any of the file modes will work there as long as I append the
&
to it.I can then re-open
STDOUT
:open STDOUT, '>>', 'log.txt'; say 'This should be logged to log.txt.';When I'm ready to change it back, I do the same thing:
open STDOUT, '>&', $STDOLD; say 'This should show in the terminal';If I only have the file descriptor, perhaps because I'm working with an old Unix programmer who thinks vi is a crutch, I can use that:
open my $fh, "<&=$fd" or die "Could not open filehandle on $fd\n";This file descriptor has a three-argument form too:
open my $fh, '<&=', $fd or die "Could not open filehandle on $fd\n";I can have multiple filehandles that go to the same place since they are different names for the same file descriptor:
use v5.10; open my $fh, '>>&=', fileno(STDOUT); say 'Going to default'; say $fh 'Going to duped version. fileno ' . fileno($fh); say STDOUT 'Going to STDOUT. fileno ' . fileno($fh);All of these print to STDOUT.
This article was originally posted on PerlTricks.com .
Jan 01, 2008 | stackoverflow.com
How do I get the full path to a Perl script that is executing? Ask Question Asked 12 years, 7 months ago Active 8 months ago Viewed 189k times
https://5a0213f7409d39e4f4257675bd947b2c.safeframe.googlesyndication.com/safeframe/1-0-38/html/container.html Report this ad
Chris Madden ,
172 38I have Perl script and need to determine the full path and filename of the script during execution. I discovered that depending on how you call the script
$0
varies and sometimes contains thefullpath+filename
and sometimes justfilename
. Because the working directory can vary as well I can't think of a way to reliably get thefullpath+filename
of the script.Anyone got a solution? perl path location Share Improve this question Follow edited Feb 18 '15 at 12:18 serenesat 4,514 10 10 gold badges 32 32 silver badges 51 51 bronze badges asked Sep 17 '08 at 16:16 Chris Madden 2,202 2 2 gold badges 15 15 silver badges 11 11 bronze badges
user1210923 ,
I know this was a long time ago but I was just looking for a perl windows way of doing this and am quite happy with my solution #!/usr/bin/perl -w my @catalog=dir
; $myHome = substr($catalog[3],14); $myHome = &rtrim($myHome); print qq(<$myHome>\n); # Right trim function to remove trailing whitespace sub rtrim { my $string = shift; $string =~ s/\s+$//; return $string; } just thought I'd share – user1210923 Dec 4 '20 at 17:42Drew Stephens , 2008-09-18 07:30:54
259There are a few ways:
$0
is the currently executing script as provided by POSIX, relative to the current working directory if the script is at or below the CWD- Additionally,
cwd()
,getcwd()
andabs_path()
are provided by theCwd
module and tell you where the script is being run from- The module
FindBin
provides the$Bin
&$RealBin
variables that usually are the path to the executing script; this module also provides$Script
&$RealScript
that are the name of the script__FILE__
is the actual file that the Perl interpreter deals with during compilation, including its full path.I've seen the first three (
$0
, theCwd
module and theFindBin
module) fail undermod_perl
spectacularly, producing worthless output such as'.'
or an empty string. In such environments, I use__FILE__
and get the path from that using theFile::Basename
module:use File::Basename; my $dirname = dirname(__FILE__);Share Improve this answer Follow edited Feb 12 '12 at 2:04 SamB 8,192 5 5 gold badges 43 43 silver badges 52 52 bronze badges answered Sep 18 '08 at 7:30 Drew Stephens 15.4k 12 12 gold badges 54 54 silver badges 81 81 bronze badgesDrew Stephens ,
This is really the best solution, especially if you already have a modified $0 – Caterham Jan 8 '12 at 1:04Ovid , 2008-09-17 16:19:48
148$0 is typically the name of your program, so how about this?
use Cwd 'abs_path'; print abs_path($0);Seems to me that this should work as abs_path knows if you are using a relative or absolute path.
Update For anyone reading this years later, you should read Drew's answer . It's much better than mine. Share Improve this answer Follow edited Jul 4 '19 at 2:47 cxw 15.4k 2 2 gold badges 37 37 silver badges 69 69 bronze badges answered Sep 17 '08 at 16:19 Ovid 11.1k 7 7 gold badges 41 41 silver badges 75 75 bronze badges
GreenGiant ,
Small comment, on activestate perl on windows $0 typically contains backslashes and abs_path returned forward slashes, so a quick "tr /\//\\/;" was needed to fix it. – Chris Madden Sep 17 '08 at 17:03Mark ,
35Use File::Spec; File::Spec->rel2abs( __FILE__ );http://perldoc.perl.org/File/Spec/Unix.html Share Improve this answer Follow edited Aug 19 '13 at 21:32 the Tin Man 151k 39 39 gold badges 197 197 silver badges 279 279 bronze badges answered Sep 17 '08 at 16:31 Mark 101k 16 16 gold badges 158 158 silver badges 219 219 bronze badges
David H. ,
Then wrap in dirname() to get the absolute path - just what I needed! – David H. Oct 4 '19 at 4:03bmdhacks , 2008-09-17 16:22:39
16I think the module you're looking for is FindBin:
#!/usr/bin/perl use FindBin; $0 = "stealth"; print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";Share Improve this answer Follow answered Sep 17 '08 at 16:22 bmdhacks 15.1k 8 8 gold badges 32 32 silver badges 55 55 bronze badges> ,
Add a commentBenjamin W. Smith ,
11You could use FindBin , Cwd , File::Basename , or a combination of them. They're all in the base distribution of Perl IIRC.
I used Cwd in the past:
Cwd:
use Cwd qw(abs_path); my $path = abs_path($0); print "$path\n";Share Improve this answer Follow edited Oct 8 '08 at 7:13 brian d foy 121k 31 31 gold badges 192 192 silver badges 549 549 bronze badges answered Sep 17 '08 at 16:29 Benjamin W. Smith 512 2 2 silver badges 6 6 bronze badgesZnik ,
@bmdhacks, you're right. Presumption is, you didn't change 0$. For example you do work above as soon as script starts (in initialization block), or elsewhere when you don't change $0. But $0 is excellent way to change process description visible under 'ps' unix tool :) This can show curren process status, etc. This is depended on programmer purpose :) – Znik Mar 3 '14 at 12:24Eric Wilhelm ,
9Getting the absolute path to
$0
or__FILE__
is what you want. The only trouble is if someone did achdir()
and the$0
was relative -- then you need to get the absolute path in aBEGIN{}
to prevent any surprises.
FindBin
tries to go one better and grovel around in the$PATH
for something matching thebasename($0)
, but there are times when that does far-too-surprising things (specifically: when the file is "right in front of you" in the cwd.)
File::Fu
hasFile::Fu->program_name
andFile::Fu->program_dir
for this. Share Improve this answer Follow edited Aug 19 '13 at 21:31 the Tin Man 151k 39 39 gold badges 197 197 silver badges 279 279 bronze badges answered Sep 18 '08 at 7:45 Eric Wilhelm 483 2 2 silver badges 2 2 bronze badgesZnik ,
Is it really likely that anyone would be so foolish as to (permanently)chdir()
at compile time? – SamB Feb 12 '12 at 21:23wnoise , 2008-09-17 16:52:24
7Some short background:
Unfortunately the Unix API doesn't provide a running program with the full path to the executable. In fact, the program executing yours can provide whatever it wants in the field that normally tells your program what it is. There are, as all the answers point out, various heuristics for finding likely candidates. But nothing short of searching the entire filesystem will always work, and even that will fail if the executable is moved or removed.
But you don't want the Perl executable, which is what's actually running, but the script it is executing. And Perl needs to know where the script is to find it. It stores this in
__FILE__
, while$0
is from the Unix API. This can still be a relative path, so take Mark's suggestion and canonize it withFile::Spec->rel2abs( __FILE__ );
Share Improve this answer Follow edited Aug 19 '13 at 21:30 the Tin Man 151k 39 39 gold badges 197 197 silver badges 279 279 bronze badges answered Sep 17 '08 at 16:52 wnoise 9,310 32 32 silver badges 46 46 bronze badgesfelwithe ,
__FILE__
still gives me a relative path. i.e. '.'. – felwithe Nov 2 '16 at 21:46Sean , 2008-09-17 16:21:33
6Have you tried:
$ENV{'SCRIPT_NAME'}or
use FindBin '$Bin'; print "The script is located in $Bin.\n";It really depends on how it's being called and if it's CGI or being run from a normal shell, etc. Share Improve this answer Follow answered Sep 17 '08 at 16:21 Sean 4,433 1 1 gold badge 17 17 silver badges 17 17 bronze badges
Znik ,
$ENV{'SCRIPT_NAME'} is empty when the script is running at console – Putnik Feb 6 '14 at 14:03Matt , 2013-07-18 23:12:45
6In order to get the path to the directory containing my script I used a combination of answers given already.
#!/usr/bin/perl use strict; use warnings; use File::Spec; use File::Basename; my $dir = dirname(File::Spec->rel2abs(__FILE__));Share Improve this answer Follow answered Jul 18 '13 at 23:12 Matt 61 1 1 silver badge 1 1 bronze badge> ,
Add a commentmoritz , 2008-09-17 16:34:54
2perlfaq8 answers a very similar question with using the
rel2abs()
function on$0
. That function can be found in File::Spec. Share Improve this answer Follow edited Aug 19 '13 at 21:31 the Tin Man 151k 39 39 gold badges 197 197 silver badges 279 279 bronze badges answered Sep 17 '08 at 16:34 moritz 12.3k 1 1 gold badge 36 36 silver badges 62 62 bronze badges> ,
Add a commentdaniel souza ,
2There's no need to use external modules, with just one line you can have the file name and relative path. If you are using modules and need to apply a path relative to the script directory, the relative path is enough.
$0 =~ m/(.+)[\/\\](.+)$/; print "full path: $1, file name: $2\n";Share Improve this answer Follow answered Jul 1 '14 at 16:19 daniel souza 332 2 2 silver badges 11 11 bronze badgesKeve ,
It does not provide the proper full path of the script if you run it like "./myscript.pl", as it would only show "." instead. But I still like this solution. – Keve Jun 27 '16 at 10:12mkc , 2012-11-26 14:01:34
1#!/usr/bin/perl -w use strict; my $path = $0; $path =~ s/\.\///g; if ($path =~ /\//){ if ($path =~ /^\//){ $path =~ /^((\/[^\/]+){1,}\/)[^\/]+$/; $path = $1; } else { $path =~ /^(([^\/]+\/){1,})[^\/]+$/; my $path_b = $1; my $path_a = `pwd`; chop($path_a); $path = $path_a."/".$path_b; } } else{ $path = `pwd`; chop($path); $path.="/"; } $path =~ s/\/\//\//g; print "\n$path\n";:DD Share Improve this answer Follow answered Nov 26 '12 at 14:01 mkc 11 1 1 bronze badge
Lee Taylor ,
Please don't just answer with code. Please explain why this is the correct answer. – Lee Taylor Nov 26 '12 at 14:21Yong Li , 2011-04-01 16:27:08
1Are you looking for this?:
my $thisfile = $1 if $0 =~ /\\([^\\]*)$|\/([^\/]*)$/; print "You are running $thisfile now.\n";The output will look like this:
You are running MyFileName.pl now.It works on both Windows and Unix. Share Improve this answer Follow edited Aug 19 '13 at 21:29 the Tin Man 151k 39 39 gold badges 197 197 silver badges 279 279 bronze badges answered Apr 1 '11 at 16:27 Yong Li 11 1 1 bronze badge
> ,
Add a commentYordan Georgiev , 2011-08-09 13:36:04
0use strict ; use warnings ; use Cwd 'abs_path'; sub ResolveMyProductBaseDir { # Start - Resolve the ProductBaseDir #resolve the run dir where this scripts is placed my $ScriptAbsolutPath = abs_path($0) ; #debug print "\$ScriptAbsolutPath is $ScriptAbsolutPath \n" ; $ScriptAbsolutPath =~ m/^(.*)(\\|\/)(.*)\.([a-z]*)/; $RunDir = $1 ; #debug print "\$1 is $1 \n" ; #change the \'s to /'s if we are on Windows $RunDir =~s/\\/\//gi ; my @DirParts = split ('/' , $RunDir) ; for (my $count=0; $count < 4; $count++) { pop @DirParts ; } my $ProductBaseDir = join ( '/' , @DirParts ) ; # Stop - Resolve the ProductBaseDir #debug print "ResolveMyProductBaseDir $ProductBaseDir is $ProductBaseDir \n" ; return $ProductBaseDir ; } #eof subShare Improve this answer Follow answered Aug 9 '11 at 13:36 Yordan Georgiev 3,986 1 1 gold badge 42 42 silver badges 47 47 bronze badgesthe Tin Man ,
While a source-only answer might solve the user's question, it doesn't help them understand why it works. You've given the user a fish, but instead you should teach them HOW to fish. – the Tin Man Aug 19 '13 at 21:28Jonathan ,
0The problem with
__FILE__
is that it will print the core module ".pm" path not necessarily the ".cgi" or ".pl" script path that is running. I guess it depends on what your goal is.It seems to me that
Cwd
just needs to be updated for mod_perl. Here is my suggestion:my $path; use File::Basename; my $file = basename($ENV{SCRIPT_NAME}); if (exists $ENV{MOD_PERL} && ($ENV{MOD_PERL_API_VERSION} < 2)) { if ($^O =~/Win/) { $path = `echo %cd%`; chop $path; $path =~ s!\\!/!g; $path .= $ENV{SCRIPT_NAME}; } else { $path = `pwd`; $path .= "/$file"; } # add support for other operating systems } else { require Cwd; $path = Cwd::getcwd()."/$file"; } print $path;Please add any suggestions. Share Improve this answer Follow edited Dec 14 '13 at 0:29 answered Dec 13 '13 at 11:57 Jonathan 1,291 2 2 gold badges 19 19 silver badges 40 40 bronze badges
> ,
Add a commentPutnik ,
0Without any external modules, valid for shell, works well even with '../':
my $self = `pwd`; chomp $self; $self .='/'.$1 if $0 =~/([^\/]*)$/; #keep the filename only print "self=$self\n";test:
$ /my/temp/Host$ perl ./host-mod.pl self=/my/temp/Host/host-mod.pl $ /my/temp/Host$ ./host-mod.pl self=/my/temp/Host/host-mod.pl $ /my/temp/Host$ ../Host/./host-mod.pl self=/my/temp/Host/host-mod.plShare Improve this answer Follow answered Feb 6 '14 at 14:39 Putnik 3,538 4 4 gold badges 26 26 silver badges 43 43 bronze badgesZnik ,
What when you call symlink? Cwd works excellent with this case. – Znik Mar 3 '14 at 12:32DavidG ,
0The problem with just using
dirname(__FILE__)
is that it doesn't follow symlinks. I had to use this for my script to follow the symlink to the actual file location.use File::Basename; my $script_dir = undef; if(-l __FILE__) { $script_dir = dirname(readlink(__FILE__)); } else { $script_dir = dirname(__FILE__); }Share Improve this answer Follow answered Apr 18 '14 at 7:56 DavidG 3,113 2 2 gold badges 25 25 silver badges 41 41 bronze badges> ,
Add a commentElmar , 2014-09-04 10:32:56
0All the library-free solutions don't actually work for more than a few ways to write a path (think ../ or /bla/x/../bin/./x/../ etc. My solution looks like below. I have one quirk: I don't have the faintest idea why I have to run the replacements twice. If I don't, I get a spurious "./" or "../". Apart from that, it seems quite robust to me.
my $callpath = $0; my $pwd = `pwd`; chomp($pwd); # if called relative -> add pwd in front if ($callpath !~ /^\//) { $callpath = $pwd."/".$callpath; } # do the cleanup $callpath =~ s!^\./!!; # starts with ./ -> drop $callpath =~ s!/\./!/!g; # /./ -> / $callpath =~ s!/\./!/!g; # /./ -> / (twice) $callpath =~ s!/[^/]+/\.\./!/!g; # /xxx/../ -> / $callpath =~ s!/[^/]+/\.\./!/!g; # /xxx/../ -> / (twice) my $calldir = $callpath; $calldir =~ s/(.*)\/([^\/]+)/$1/;Share Improve this answer Follow answered Sep 4 '14 at 10:32 Elmar 1> ,
Add a commentdrjumper , 2018-10-23 08:51:38
0None of the "top" answers were right for me. The problem with using FindBin '$Bin' or Cwd is that they return absolute path with all symbolic links resolved. In my case I needed the exact path with symbolic links present - the same as returns Unix command "pwd" and not "pwd -P". The following function provides the solution:
sub get_script_full_path { use File::Basename; use File::Spec; use Cwd qw(chdir cwd); my $curr_dir = cwd(); chdir(dirname($0)); my $dir = $ENV{PWD}; chdir( $curr_dir); return File::Spec->catfile($dir, basename($0)); }Share Improve this answer Follow answered Oct 23 '18 at 8:51 drjumper 71 3 3 bronze badges> ,
Add a commentuser3228609 , 2019-10-16 15:39:42
0On Windows using
dirname
andabs_path
together worked best for me.use File::Basename; use Cwd qw(abs_path); # absolute path of the directory containing the executing script my $abs_dirname = dirname(abs_path($0)); print "\ndirname(abs_path(\$0)) -> $abs_dirname\n";here's why:
# this gives the answer I want in relative path form, not absolute my $rel_dirname = dirname(__FILE__); print "dirname(__FILE__) -> $rel_dirname\n"; # this gives the slightly wrong answer, but in the form I want my $full_filepath = abs_path($0); print "abs_path(\$0) -> $full_filepath\n";Share Improve this answer Follow edited Oct 16 '19 at 16:01 answered Oct 16 '19 at 15:39 user3228609 1 1 1 bronze badge> ,
Add a commentuser3673 , 2020-08-23 17:39:37
0use File::Basename; use Cwd 'abs_path'; print dirname(abs_path(__FILE__)) ;Drew's answer gave me:
'.'
$ cat >testdirname use File::Basename; print dirname(__FILE__); $ perl testdirname .$ perl -v This is perl 5, version 28, subversion 1 (v5.28.1) built for x86_64-linux-gnu-thread-multi][1]Share Improve this answer Follow answered Aug 23 '20 at 17:39 user3673 496 3 3 silver badges 17 17 bronze badges> ,
Add a commentuser3061015 ,
-2What's wrong with
$^X
?#!/usr/bin/env perl<br> print "This is executed by $^X\n";Would give you the full path to the Perl binary being used.
Evert Share Improve this answer Follow edited Dec 3 '13 at 11:06 Eugene Loy 11.6k 8 8 gold badges 47 47 silver badges 73 73 bronze badges answered Dec 3 '13 at 10:48 user3061015 1 2 2 bronze badges
Putnik ,
It gives path to the Perl binary whilst path to a script required – Putnik Feb 6 '14 at 14:00
Oct 15, 2020 | perlmonks.org
syphilis on Oct 14, 2020 at 02:26 UTC
e: remove first and last character of stringi've thought of using substr but i can't be sure that the number above in quotes will always be the same number of characters
You can use substr() without knowing the number of characters.
To remove the first character of $str: substr($str, 0, 1, '')
To remove the last character of $str : substr($str, -1, 1, '')
Or remove the last character of $str : substr($str, length($str) - 1, '')
Or, just use chop() to remove the last character, as you've already noted.Cheers,
RobrsFalse on Oct 14, 2020 at 06:41 UTC
Re: remove first and last character of stringTo delete the first and the last character: for( 1 .. 2 ){ $string = reverse $string; chop $string; } [download]
kcott on Oct 14, 2020 at 09:09 UTC
Re: remove first and last character of stringG'day flieckster ,
"what is the best way to remove the first and last character, or remove the "" from the variable ?" [my emphasis]If you only need to remove the leading and trailing quotes, and the example data you provided is representative, i.e. no embedded quotes, the easiest and most efficient way to do this would be by using transliteration :
$string =~ y/"//d [download]Here's a quick, yet complete, command line example:
$ perl -E 'my $x = q{"654321_1111"}; say $x; $x =~ y/"//d; say $x' "654321_1111" 654321_1111 [download][Aside: In his book, " Perl Best Practices ", Damian Conway used the term transobliteration to describe this particular usage.]
-- KenAnomalousMonk on Oct 14, 2020 at 07:11 UTC
Re^2: remove first and last character of string
by AnomalousMonk on Oct 14, 2020 at 07:11 UTCIt's not clear to me if flieckster intends to deal only with strings like '"foo"' (from which it is clear that 'foo' should be extracted), or if he or she may also be dealing with strings like 'foo' '"foo' 'foo"' 'f"o"o' etc., i.e., strings not having double-quotes at both the start and end of the string.
In the latter case, it should be noted that
Give a man a fish : <%-{-{-{-<
qr/^\"(.+)\"$/
will not match and will return an empty list, leaving $got undefined.AnomalousMonk on Oct 14, 2020 at 17:17 UTC
Re: remove first and last character of stringAs with others who have commented in this thread, it's not clear to me just what flieckster wants to achieve.
If, and it's a big if, the aim is to remove double-quotes only when they are paired at both the start and end of the string and never in any other circumstance, then
qr{ (?| \A " (.*) " \z | (.*)) }xms # needs 5.10+
will do the trick. With this regex,
'""' '""""' '"foo"' '"fo"o"' '"f"o"o"'
become
'' '""' 'foo' 'fo"o' 'f"o"o'
respectively, while strings like
'' '"' '"foo' 'foo"' 'f"oo' 'f"o"o'
are unchanged.Note that this regex needs Perl version 5.10+ because it uses the (?|...) branch reset regex extension. The regex can be made to work in pre-5.10 versions by removing the (?|...) and adding a grep defined, ... filter to the output of the regex match.
Oct 12, 2020 | perlmonks.org
likbez
my $a=$x=$y=$z = foo()Here my attribute does not propogate like in case of comma. It applies only to $a, right ? But now the fun starts But now the fun startsDB<3> use v5.10 DB<4> my $a=$x=$y=$z = 1 DB<5> say "|$a|$x|$y|$z|" ||1|1|1| DB<6> unless( defined($a) ){ say "a is undefined"} a is undefinedwhy $a remains uninitialized?LanX on Oct 12, 2020 at 07:22 UTC
Re^3: What's happening in this expression? > why $a remains uninitialized? It's not the same It's not the same $a The lexical scope in the debugger is limited to the The lexical scope in the debugger is limited to the The lexical scope in the debugger is limited to the eval'ed line. Skip the my to avoid this effect.Fletch on Oct 12, 2020 at 03:25 UTC ( # 11122722 = note : print w/replies , xml ) Need Help??edit
Fletch already explained it in detail
in reply to Re^2: What's happening in this expression? (Updated)
in thread What's happening in this expression?The debugger is a bad place to play with scoping like this. In effect when you evaluate single lines like this they're more like doing an eval within the scope of the program (more or less; I'm sure someone more familiar with the perl5db could give more specifics).
It's kind of like (handwaving) textually shimming in say DebugDump( eval { YOURTEXTHERE } ) into wherever you're looking at and seeing the result.
This means that your my declaration is happening inside of a transient scope (that single eval statement) and then it's going away. Since the my was affecting only $a when you check for defined-ness it fails because the package $a wasn't defined (however your modifications to $x et al changes the package versions of those and the values do persist after the statement).$ cat test.pl use 5.032; my $foo = 10; say qq{foo: $foo} $ perl -d test.pl Loading DB routines from perl5db.pl version 1.57 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(test.pl:2): my $foo = 10; DB<1> x $foo 0 undef DB<2> n main::(test.pl:3): say qq{foo: $foo} DB<2> x $foo 0 10 DB<3> my $foo = 20 DB<4> x $foo 0 10 DB<5> my $foo = 20; say qq{foo: $foo} foo: 20 DB<6> x $foo 0 10 [download]
Simple rule of thumb I tend to follow is just don't use my (or state or our ) from the debugger command line to try and affect anything outside of that immediate command line.
The cake is a lie.
The cake is a lie.
The cake is a lie.
likbez on Oct 15, 2020 at 04:08 UTC
Re^4: What's happening in this expression? (Updated)You are right. My variables are not always treated correctly, although recently the situation improved. I remember that in the past you just can't work with my variables at all. I just have a utility that stripped my moving them to tail comments and then reversed the situation. But now the usage of my "official" as it is forced by the strict pragma. Which means that such a situation is less acceptable.
Also if you are using recursion my attribute can't be stripped at all. So this is a clear deficiently.
That's sad, because IMHO the debugger is the crown jewel of Perl language environment and remains in certain areas unmatched by competition(macros, flexibility of c command, etc.) Possibility of b lineno ($var eq "value") is indispensable for debugging complex programs. That's what I always stress in my Perl advocacy efforts" "Unmatched by competition."
So any deficiencies here are "highly undesirable."
That's, of course, raises the question of development priorities...
Oct 15, 2020 | perlmonks.org
by Discipulus
on Sep 30, 2020 at 08:45 UTC ( # 11122359 = perlmeditation : print w/replies , xml ) Need Help?? Only Perl can teach Perl
- log likbez out
- likbez
- The Monastery Gates
- Seekers of Perl Wisdom
- Meditations
- Cool Uses For Perl
- Obfuscation
- Q&A
- Tutorials
- Poetry
- Reviews
- Perl News
- Donate
- Recent Threads
- Newest Nodes
- Super Search
- PerlMonks Discussion
- What's New
Discipulus IntroductionThis is the follow up of Perl Automateaching -- part 1: brainstorming so read it first to have an idea of my intentions even if the pseudocode presented there is not what I currently plan.
I have choosen the name for this project and it will be Perl::Teacher as it is clear and explicative.
This post is a mere proof of concept about Perl teaching and, yes! it can be done! I'd like to be billionaire to hire super skilled perl geeks to develop my idea... but let's say they are all busy at the moment :) so the pupil ( discipulus in Latin) will squeeze his brain and will dress teacher dresses. Contributors are welcome!
In the final form Perl::Teacher will be document oriented, ie: it will analyze perl programs wrote by the pupil in physical files. But in the current proof of concepts various student's attempts are hardcoded into the below program contained in scalars from $work_01 to $work_n and with a $solution_code
Also the final form of Perl::Teacher will be a bit interactive presenting and reviewing assignements and telling small lessons, but for the moment nothing of this is done.
So running the below program you will see a serie of attempts to satisfy the assignemnt and results of tests applied to provided code fragments.
Modify the $debug variable to 1 or 2 to see much more messages.
Proof of conceptHere my efforts up now ( Ignore the warning you'll receive: Having more than one /x regexp modifier is deprecated at .../perl5.24-64b/perl/site/lib/Perl/Critic/Policy/ValuesAndExpressions/RequireInterpolationOfMetachars.pm line 110. beacuse it is a problem of Perl::Critic itself: see resolved issue on github )
use strict; use warnings; use PPI; use PPI::Dumper; use Perl::Critic; use Test::Deep::NoTest; use Data::Dump; my $debug = 0; # 0..2 my $perl_critic_severity = 'gentle'; # 'gentle' 'stern' 'harsh' 'crue + l' 'brutal' # assignemnt print <<'EOP'; Assignement: -Create an array named @letters with 5 elements and fill it with first + 5 letters of the English alphabet -Remove the first element using a list operator and assign it to a sca + lar variable -Remove the last element using a list operator and assign it to a scal + ar variable -Join these two removed elements with a '-' (using single quotes) sign + and assign the result to a scalar named $result NB: All variables have to be lexically scoped NB: each above steps must be accomplished in one statement EOP # solution code my $solution_code = <<'EOC'; use strict; use warnings; my @letters = ('a'..'e'); my $first = shift @letters; my $last = pop @letters; my $result = join '-', $first, $last; EOC # student attempts my $work_01 = <<EOT; need to crash! EOT my $work_02 = <<EOT; # comment: no need to crash! EOT my $work_03 = <<EOT; # comment: no need to crash! use strict; EOT my $work_04 = <<EOT; # comment: no need to crash! use strict; use warnings; EOT my $work_05 = <<'EOT'; use strict; use warnings; my @letters = ('a'..'e'); EOT my %tests = ( # TEST DESCRIPTION # number => anonymous hash (tests will be executed in a sorted + order) # name => # run => send the code to a sub returning 0|1 plus + messages # select_child_of => given a PPI class search each element + of such class # to see if they contain all required el + ements. # returns 0|1 plus messages # class => the class of elements to analyze (all el + ements of such class will be tested) # tests => anonymous array: check children of the c + urrent element to be of the appropriate class # and to hold the desired content (string + or regex can be used) # evaluate_to => optional but only possible if select_child + _of was used: the DPOM fragment # extracted by select_child_of will be chec + k to hold a precise value (at runtime: see below) # hint => # docs => 001 => { name => 'code compiles', run => \&test_compile, # select_child_of ... # evaluate_to ... hint => "comment the line causing crash with a # in fro + nt of it", docs => ['perldoc perlintro', 'https://perldoc.perl.org + /perlintro.html#Basic-syntax-overview'], }, 002 => { name => 'strictures', # run => ... select_child_of => { class => 'PPI::Statement::Include', tests => [ #['PPI::Token::Word', 'use'], ['PPI::Token::Word', qr/^use$/], ['PPI::Token::Word', 'strict'] ], }, # evaluate_to ... hint => "search perlintro for safety net", docs => ['https://perldoc.perl.org/perlintro.html#Safet + y-net'], }, 003 => { name => 'warnings', # run => ... select_child_of => { class => 'PPI::Statement::Include', tests => [ ['PPI::Token::Word', 'use'], #['PPI::Token::Word', qr/^use$/], ['PPI::Token::Word', 'warnings'] ], }, # evaluate_to ... hint => "search perlintro for safety net", docs => ['https://perldoc.perl.org/perlintro.html#Safet + y-net'], }, 004 => { name => 'array creation', select_child_of => { class => 'PPI::Statement::Variable', tests => [ ['PPI::Token::Word', 'my'], ['PPI::Token::Symbol', '@letters'], ['PPI::Token::Operator', '='], ], }, evaluate_to => [ ('a'..'e') ], hint => "search perlintro basic variable types", docs => ['https://perldoc.perl.org/perlintro.html#Perl- + variable-types'], }, 005 => { name => 'first element of the array', select_child_of => { class => 'PPI::Statement::Variable', tests => [ ['PPI::Token::Word', 'my'], ['PPI::Token::Symbol', qr/\$[\S]/], ['PPI::Token::Operator', '='], ['PPI::Token::Word', 'shift'], ['PPI::Token::Symbol', '@letters'], ], }, evaluate_to => \'a', hint => "search functions related to real arrays", docs => ['https://perldoc.perl.org/5.32.0/perlfunc.html + #Perl-Functions-by-Category'], }, 006 => { name => 'last element of the array', select_child_of => { class => 'PPI::Statement::Variable', tests => [ ['PPI::Token::Word', 'my'], ['PPI::Token::Symbol', qr/\$[\S]/], ['PPI::Token::Operator', '='], ['PPI::Token::Word', 'pop'], ['PPI::Token::Symbol', '@letters'], ], }, evaluate_to => \'e', hint => "search functions related to real arrays", docs => ['https://perldoc.perl.org/5.32.0/perlfunc.html + #Perl-Functions-by-Category'], }, 007 => { name => 'final result', select_child_of => { class => 'PPI::Statement::Variable', tests => [ ['PPI::Token::Word', 'my'], ['PPI::Token::Symbol', '$result'], ['PPI::Token::Operator', '='], ['PPI::Token::Word', 'join'], ['PPI::Token::Quote::Single', "'-'"], ['PPI::Token::Operator', ','], ['PPI::Token::Symbol', qr/^\$[\S]/], ['PPI::Token::Operator', ','], ['PPI::Token::Symbol', qr/^\$[\S]/], ], }, evaluate_to => \'a-e', hint => "search functions related to strings", docs => ['https://perldoc.perl.org/5.32.0/perlfunc.html + #Perl-Functions-by-Category'], }, ); # student's attempts examination foreach my $code ( $work_01, $work_02, $work_03, $work_04, $work_05, $ + solution_code){ $code = PPI::Document->new( \$code ); print "\n# START of provided code:\n",$code=~s/^/| /gmr,"# END of + provided code\n# TESTS:\n"; PPI::Dumper->new($code)->print if $debug > 1; my $passed_tests; foreach my $test (sort keys %tests){ print "DEBUG: starting test $test - $tests{ $test }{ name }\n" + if $debug; # if run defined my $run_result; my $run_msg; if ( exists $tests{ $test }{ run } ){ ($run_result, $run_msg) = $tests{ $test }{ run }->( $code + ); if ( $run_result ){ print "OK test [$tests{ $test }{ name }]\n"; $passed_tests++; # next test next; } else{ $run_msg =~ s/\n//; print "FAILED test [$tests{ $test }{ name }] because: + $run_msg\n"; if ( $tests{ $test }{ hint } ){ print "HINT: $tests{ $test }{ hint }\n"; } if ( $tests{ $test }{ docs } ){ print map {"DOCS: $_\n"} @{$tests{ $test }{ docs } + } ; } last; } } # select_child_of defined my $candidate_pdom; my $select_child_of_msg; if ( exists $tests{ $test }{ select_child_of } ){ ($candidate_pdom, $select_child_of_msg) = select_child_of( pdom => $code, wanted_class => $tests{ $test }{ select_child_of } + { class }, tests => $tests{ $test }{ select_child_of }{ tests + } ); } # also evaluation is required if( $candidate_pdom and exists $tests{ $test }{ evaluate_to } + ){ my ($evauleted_pdom, $eval_msg) = evaluate_to ( $candidate_pdom, $tests{ $test }{ evalua + te_to } ); if($evauleted_pdom){ print "OK test [$tests{ $test }{ name }]\n"; $passed_tests++; # jump to next test next; } else{ print "FAILED test [$tests{ $test }{ name }] becau + se: $eval_msg\n"; if ( $tests{ $test }{ hint } ){ print "HINT: $tests{ $test }{ hint }\n"; } if ( $tests{ $test }{ docs } ){ print map {"DOCS: $_\n"} @{$tests{ $test }{ do + cs }} ; } } } elsif( $candidate_pdom ){ print "OK test [$tests{ $test }{ name }]\n"; $passed_tests++ ; # jump to next test next; } else{ print "FAILED test [$tests{ $test }{ name }] because: $sel + ect_child_of_msg\n"; if ( $tests{ $test }{ hint } ){ print "HINT: $tests{ $test }{ hint }\n"; } if ( $tests{ $test }{ docs } ){ print map {"DOCS: $_\n"} @{$tests{ $test }{ docs }} ; } # if one test breaks end the testing loop last; } } # all tests passed if ( $passed_tests == scalar keys %tests ){ print "\nALL tests passed\n"; my $critic = Perl::Critic->new( -severity => $perl_critic_sev + erity ); my @violations = $critic->critique($code); if ( @violations ){ print "Perl::Critic violations (with severity: $perl_criti + c_severity):\n"; print @violations; } else{ print "No Perl::Critic violations using severity level: $p + erl_critic_severity\n"; } } print "\n\n"; } ################################ # TESTS ################################ sub evaluate_to{ my $pdom = shift; # passed by reference my $expected_value = shift; ############################### # VERY DIRTY TRICK - START ############################### # only last element is returned in string evaluation # so the below code cuts the parent where the current # pdom is found. so the current statement will be the # last one of the whole code (parent) and its value # returned by the string evaluation # (probably I'll need to redirect STDOUT in this scope) # # NB this will fail for multiline statements! my $pdom_parent = $pdom->parent; my @lines_od_code = split/\n/,$pdom_parent->content; if ( $debug > 1 ){ print "ORIGINAL CODE:\n"; dd @lines_od_code; print "FOUND current PDOM element at line: ", $pdom->line_numb + er, "\n"; print "CUTTING code at line: ", $pdom->line_number, "\n"; dd @lines_od_code[0..$pdom->line_number-1] } $pdom = PPI::Document->new( \join"\n",@lines_od_code[0..$pdom->lin + e_number-1] ); ############################### # VERY DIRTY TRICK - END ############################### { local $@; my $got; # we expect a scalar ref if ( ref $expected_value eq 'SCALAR' ){ $got = \eval $pdom ; } # we expect an array ref elsif ( ref $expected_value eq 'ARRAY' ){ $got = [ eval $pdom ]; } # we expect a hash ref elsif ( ref $expected_value eq 'HASH' ){ $got = { eval $pdom }; } # we expect a regexp ref elsif ( ref $expected_value eq 'Regexp' ){ $got = eval $pdom; $got = qr/$got/; } # Not a reference else{ $got = eval $pdom; } # check to be the same type if ( ref $expected_value ne ref $got ){ return (0, "got and expected values are not of the same ty + pe") } else{ print "DEBUG: OK both got and expected are of the same typ + e: ", ref $got,"\n" if $debug; } if ( eq_deeply( $got, $expected_value ) ){ if ( $debug > 1 ){ print "DEBUG: OK both got and expected hold sa + me content: "; dd $got; } return ($pdom, "expected value found for the expre + ssion [$pdom]"); } else{ if ( $debug ){ print "GOT: ",ref $got,"\n"; dd $got; print "EXPECTED: ",ref $expected_value,"\n"; dd $expected_value; #print "PARENT: "; PPI::Dumper->new( $pdom->parent )-> + print; } return (0, "wrong value of the expression [$pdom]") } } } sub select_child_of{ my %opt = @_; my $pdom_fragments = $opt{ pdom }->find( $opt{ wanted_class } ); return (0, "no element found of the correct type") unless $pdom_fr + agments; foreach my $pdom_candidate ( @$pdom_fragments ){ print "DEBUG: checking fragment: [$pdom_candidate]\n" if $debu + g; my $expected_ok; foreach my $test ( @{$opt{ tests }} ){ my ($class, $content) = @$test; print "DEBUG: testing for class [$class] and content [$con + tent]\n" if $debug; if ( $pdom_candidate->find( sub { $_[1]->isa($class) and ( ref $content eq 'R + egexp' ? ( $_[1]->content = + ~ /$content/ ) : ( $_[1]->content e + q $content ) ) } ) ){ $expected_ok++; #print "DEBUG FOUND: [",ref $_[1],"] [",$_[1]->content + ,"]\n"; print "DEBUG: OK..\n" if $debug; if ( $expected_ok == scalar @{$opt{ tests }} ){ print "DEBUG: found a good candidate: [$pdom_candi + date]\n" if $debug; return ( $pdom_candidate, "found expected code in: + [$pdom_candidate]" ) } } else{ print "DEBUG: FAIL skipping to next fragment of co + de\n" if $debug; last; } } } #FAILED return (0,"element not found") } sub test_compile{ my $code = shift; { local $@; eval $code; if ( $@ ){ # print "\$@ = $@"; return (0, $@, "Comment the line with a # in front of it", + "perlintro" ); } else { # $code instead of 1?????? return (1, "code compiles correctly"); } } } [download] Implementation (current)As you can see there is a lot PPI stuff but not exclusively. Tests are execuded in order from 001 to 00n and if a test fails the current mini program is rejected.
Each test can contain different steps, the first one being the optional run that simply sends the current code to a sub: this preliminary, optional test passes if the sub returns 1 and fails otherwise. Here it is used only to check if the program compiles ( see below for future ideas ).
The second step of a test is select_child_of and it expects a PPI class name and a serie of subtests. Each PPI element of the specified PPI class, for example PPI::Statement::Variable (a variable declaration) will be processed to see if they contains PPI elemnts which satisfy all subtests. The first PPI element passing all subtests is returned by select_child_of and becomes a candidate for further inspections.
Infact if evaluate_to is also specified, the current PPI element is, take a deep breath, keep calm, string evaluated to see if it holds the wanted value. And hic sunt leones or here are dragons because eval only returns the last statement value. Search the code above for the string dirty trick to see my workaround. For me it is a genial solution, but wait, I'm the guy who string eval'ed entire CPAN.. :) so improvements are warmly welcome.
This form of testing is a proof of concepts: is not the final form of the testing framework needed by Perl::Teacher
When a miniprogram passes all tests it is evaluated by Perl::Critic to give more hints to the student. Eventual policy violations will not make the program to be marked as wrong, but are just presented as suggestions.
A note about flexibilty: looking carefully at the assignement you will notice that @letters and $result are constraints. Not the same for the intermediate scalars containing the first element and the last one.
Implementation (future)module designThe main Perl::Teacher module will provide only a framework to produce courses. The $teacher will load or create a configuration will have methods to deal with the student's input and to emit messages, but the main activity will be to load and follow courses plugins of the class Perl::Teacher::CourseIn my idea the course creator will publish Perl::Teacher::Course::EN::BasicVariables or Perl::Teacher::Course::IT::RegexIntroduzione all being child of the main Perl::Teacher::Course class. These courses have to be pluggable to the $teacher object ( Module::Pluggable probably but I have to investigate it further)
Each course will contain a serie of lessons published a sub modules, as in Perl::Teacher::Course::EN::BasicVariables::01_strings , ..::02_lists etc.
Yes I know: very long names.. but this will ensure a clarity of intent and of usage, in my opinion.
( update October 14 2020 see the related question Module design for loadable external modules containing data )
lessonsEach lesson will contain an ordered serie of optional elements: zero one or more assignement , multiple test elements possibly interleaved by one or more discourse and direct question .
So a possible flow can be:
01 - discourse - introduction to the lesson 02 - discourse - more words 03 - assignement 04 - test 05 - test - more test 06 - test - test test ( block until all tests are ok ) 07 - discourse - explain and add a task 08 - assignement - the main assignement is updated 09 - test 10 - test - more test 11 - test - test test ( block until all tests are ok ) 12 - question 13 - question 14 - discourse - explaining answers ... nn - discourse - TIMTOWTDI nn - discourse - see also [download]Suggestions on module design are warmly welcome, but i want to keep it as simple as possible, not spawning objects for everything.
testsTests presented in the above code are too semplicistics to cover each teaching activity. I need beside positive tests also negative ones for example to prevent the use of modules, or all modules but one, to prevent external program execution and so on. Theese tests will be quite on success and will emit messages only on failure: "dont do this!".
I can use Test::Script to add tests about correct overall syntax check, behaviour of STDOUT and STDERR given different arguments and so on.
Then Perl::Teacher will provide its own tests like ones presented above: evaluate_to ( evaluate_at is probably a better name as it eval the code at a certain line), is dirty but it seems to me a viable option not so risky given the super small and controlled environment. I also plan a method named evaluate_subs which will grab al subs to test them.
I have to mix all this features in a clean and easy to use interface. Suggetions are welcome.
student interactionDuring a lesson the student must have the possibility to review the current assignement, to receive hints and be pointed to relevant documentation. Part of this is roughly done in the presented code using hints and docs embedded in tests. Can be and must be improved.
I like to add a TIMTOWTDI discourse at the end of each lesson showing more ways to accomplish, even if not in the very same way, the assignement.
Every output, comprensive of examined code, errors and hints, emitted during 03_array_manipulation must be saved into a 03_array_manipulation.history file so that the student can review the whole lesson including errors commited and pitfalls and the solution alongside different approaches to the same problem. Passing the time this becomes a good source of knoweledge.
further ideasTesting standalone scripts is an idea haunting me since years. Modulino is an approach. I can be mad enough to take the original PDOM of a given program, then save all subs and use PPI method prune to delete them from the PDOM, then wrap the rest into a new main_original_program sub, add it to a new PDOM along with all previously saved subs. Then I could do the obtained file and test it nicely. A lot of cut 'n paste and probably error prone, but can be a path to explore.
I'd like also my Perl::Teacher to be as much possible input/output agnostic: implement a way to interact with the console leaving open the possibility to be used by a web interface too: how to do this?
I'd like to ear your opinions about this project, sugesstions on module design and implementation of its parts, comments to the above proof concepts and everything you want to share.
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.Tux on Sep 30, 2020 at 13:29 UTC
Re: automateaching -- part 2: proof of conceptFeel free to use in the TIMTOWTDI section :)
Assignment should clearly state capitals or lower case. (assumed lower case below).
This was too much of "I could not rest" to resist:
Read more... (8 kB)
Enjoy, Have FUN! H.MerijnDiscipulus on Oct 01, 2020 at 09:24 UTC
Re^2: automateaching -- part 2: proof of conceptTux ,
by Discipulus on Oct 01, 2020 at 09:24 UTCThanks for sharing your TIMTOWTDIness :)
Taking it seriously it demonstrate an important concept: learning is a path to follow, possibly alongside a teacher. Many of us can produce ten different ways to satisfy an assignment using perl. But this is not the point.
As you noticed (lack of lower case specification for the array and the costraint of a single quote for the dash) it is very important to be clear in the assignement, making it also pedantic, and to be sure it imply the usage of already presented elements.
A teacher must introduce concepts and verify how much students have incorporated them.
Teaching, at first, is dedicated to fill ignorant's gap with notions and concepts (then teach how to learn and how to think, but is not my goal).
So a course (in general but also mines) starts with assumed ignorance in one field, and step by step introduces elements and tests the overall students understanding.
To produce PPI tests making all your example to be verified is an immane task, not worth even to plan. While teaching or learning the appropriate virtue is patience not hubris infact to learn is fondamental to recognize somethig superior who teach you.
So I can add this note to my Perl::Teacher project:
about assignements: -be sure to imply only already introduced elements, possibly refering + to the lesson where they were discussed -in the hints section put reminders to previous lessons -be pedantic in the assignement -possibly show up what was expected by tests when datastructures are i + nvolved (this can clarify an assignement) [download]Tux !! out of the classroom!! :)
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
- Comment on automateaching -- part 2: proof of concept
- Select or Download Code
- Send private /msg to Discipulus
Replies are listed 'Best First'.
Oct 15, 2020 | www.toptal.com
References are used frequently and extensively in Perl code. They're very important for a Perl web developer to understand, as the syntax of element access changes depending on whether you have a reference or direct access.
Q: In Perl, how do you initialize the following?
an array
an array reference
A hash
A hash reference
Furthermore, how would you change an array to an array reference, a hash to a hash reference, and vice versa? How do you access elements from within these variables?
A: The use of hash and array references is a pretty basic concept for any experienced Perl developer, but it may syntactically trip up some newer Perl developers or developers who never really grasped the underlying basics.Initializing an Array:my @arr = (0, 1, 2);An array is initialized with an
@
symbol prefixed to the variable name, which denotes the variable type as an array; its elements are placed in parentheses.Initializing an Array Reference:my $arr_ref = [0, 1, 2];With an array reference, you use the
$
symbol, which denotes 'scalar', and the elements are placed in square brackets. The reference isn't specified as an array, just as a scalar, so you have to be careful to handle the variable type appropriately.With hashes, the syntax is similar.
Initializing a Hash:my %hash = (0 => 'First', 1 => 'Second', 2 => 'Third');Just as with an array, the elements of a hash are defined with parentheses, but since the variable is a hash, it's prefixed with a
%
.Initializing an Array Reference:my $hash_ref = {0 => 'First', 1 => 'Second', 2 => 'Third'};Like an array reference, a hash reference variable is prefixed with a
$
, but the elements are placed in curly braces.Referencing a Hash or an ArrayReferencing an array or hash is pretty straightforward. In Perl, a backslash in front of a variable will return the reference to it. You should expect something like the following:
my $arr_ref = \@arr; my $hash_ref = \%hash;DereferencingDereferencing a referenced variable is as easy as reassigning it with the appropriate variable identifier. For example, here's how you would dereference arrays and hashes:
my @arr = @$arr_ref; my %hash = %$hash_ref;Accessing ElementsThe differences between accessing elements of these variable types and their reference versions is another area where amateur developers may get tripped up.
# to access an element of an array my $element = $arr[0];Notice that for an array you are not using the
@
prefix but rather the$
to denote a scalar, which is the type returned when accessing any element of an array. Accessing the elements of an array reference, a hash, and a hash reference follows a similar syntax:# to access an element of an array reference my $element = ${$array_ref}[0]; # to access an element of a hash my $element = $hash{0}; # to access an element of a hash reference my $element = $hash_ref->{0};
Oct 15, 2020 | www.geeksforgeeks.org
DB<15> b valuedirThis creates a breakpoint at the very first executable statement of the subroutine valuedir.
b-command can also be used to halt a program only when a specified condition meets.
For example, below mentioned command tells the debugger to halt when it is about to execute line 12 and the variable $vardir is equal to the null string:DB<15> b 12 ($vardir eq "")Any legal Perl conditional expression can be specified with the b statement.
Jan 01, 2017 | stackoverflow.com
Ask Question Asked 3 years ago Active 2 years ago Viewed 6k times
https://tpc.googlesyndication.com/safeframe/1-0-37/html/container.html Report this ad
Stephen , 2017-10-03 16:52:57
17 7I have never fully understood Perl's resolution of package names, but I always assumed that the following should always work, assuming you are executing myscript.pl from within the directory that contains it:
myscript.pl (contains the following statement: use Class1::Class2::Class3) Class1/ Class2/ Class3.pm (contains the following package declaration: package Class1::Class2::Class3;)However, this is not working in my code because Class3.pm cannot be located. Looking at @INC, it does not include the current directory, only various directories of my Strawberry Perl installation.
What is the recommended way to solve this? I suppose I could modify @INC, or I could start using FindBin, but I'm not sure which is best. I have inherited this code and am simply migrating it to a new location, but it doesn't look like the old code needed either such solution (I could be wrong, still looking...) perl share edit follow edited Nov 21 '17 at 15:50 ikegami 308k 14 14 gold badges 213 213 silver badges 452 452 bronze badges asked Oct 3 '17 at 16:52 Stephen 5,308 5 5 gold badges 34 34 silver badges 66 66 bronze badges
> ,
add a comment 3 Answers Active Oldest Votesikegami ,
30Perl doesn't search the current directory for modules or the script's directory for modules, at least not anymore. The current directory was removed from
@INC
in 5.26 for security reasons.However, any code that relies on the current directory being in
@INC
was buggy far before 5.26. Code that did so, like yours, incorrectly used the current directory as a proxy for the script's directory. That assumption is often incorrect.To tell Perl to look in the script's directory for modules, use the following:
use FindBin 1.51 qw( $RealBin ); use lib $RealBin;or
use Cwd qw( abs_path ); use File::Basename qw( dirname ); use lib dirname(abs_path($0));share edit follow edited Oct 4 '18 at 8:27 answered Oct 3 '17 at 17:39 ikegami 308k 14 14 gold badges 213 213 silver badges 452 452 bronze badgesikegami ,
A tangential question, but why$RealBin
and not just$Bin
? Does having the links resolved give us any benefit here, or have you used it here just a general good practice? – sundar - Reinstate Monica Apr 9 '18 at 12:19melpomene , 2017-10-03 17:00:02
9Having
.
(the current directory) in@INC
was removed in 5.26 for security reasons ( CVE-2016-1238 ). Some Linux distributions have backported the change, so you might run into this problem even if you're using e.g. 5.24. share edit follow edited Oct 3 '17 at 17:44 answered Oct 3 '17 at 17:00 melpomene 77.6k 6 6 gold badges 63 63 silver badges 117 117 bronze badgesmelpomene ,
@ikegami Oh, interesting. I didn't know FindBin was fixed. It did search$PATH
until version 1.51, released with perl 5.16. – melpomene Oct 3 '17 at 17:42> ,
7Perl 5.26 removed having the current working directory in
@INC
as a security measure.It's explained in the 5.26 perldelta notes .
perlsyn - Perldoc Browser
A BLOCK by itself (labeled or not) is semantically equivalent to a loop that executes once. Thus you can use any of the loop control statements in it to leave or restart the block. (Note that this is NOT true in
eval{}
,sub{}
, or contrary to popular beliefdo{}
blocks, which do NOT count as loops.) Thecontinue
block is optional.The BLOCK construct can be used to emulate case structures.
SWITCH: { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $nothing = 1; }You'll also find that
foreach
loop used to create a topicalizer and a switch:SWITCH: for ($var) { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $nothing = 1; }Such constructs are quite frequently used, both because older versions of Perl had no official
switch
statement, and also because the new version described immediately below remains experimental and can sometimes be confusing.
Jan 01, 2011 | stackoverflow.com
Asked 9 years, 7 months ago
CMS , 2011-03-02 12:31:46
9 1Can I set PERL5LIB in a separate script and call that script in other scripts? How do I do it? And how would it affect the script in which it is used?
Thanks. perl share improve this question follow asked Mar 2 '11 at 12:31 CMS 113 1 1 gold badge 1 1 silver badge 6 6 bronze badges
add a comment 5 Answers Active Oldest VotesEugene Yarmash ,
7Setting
PERL5LIB
at runtime will not affect Perl's search path. You need to export the variable before executing the interpreter.
Alternatively you can modify@INC
at compile time (also possible to do in a separate script/module):BEGIN { unshift @INC, "/path/to/dir" }This is what the
lib
pragma does. share improve this answer follow edited Mar 2 '11 at 14:35 answered Mar 2 '11 at 12:55 Eugene Yarmash 112k 29 29 gold badges 251 251 silver badges 316 316 bronze badgesMark ,
This doesn't work for me, I think because the PERL5LIB environment variable is processed by the interpreter before the script is executed, so @INC isn't modified. – Mark Mar 2 '11 at 13:25Mark , 2011-03-02 13:11:54
4You'd do this via 'use lib' rather than manipulating the environment:
use lib '/home/perl5';That could be in a separate file that you 'require' in. share improve this answer follow edited Mar 2 '11 at 13:24 answered Mar 2 '11 at 13:11 Mark 431 3 3 silver badges 6 6 bronze badges
> ,
add a commentzrajm , 2014-05-20 11:05:43
1
PERL5INC
is a shell environment variable, so you wouldn't set it inside your Perl program (normally) but instead specify it before invoking Perl. The below is a shell command where I've usedPERL5LIB
to instructprove
to find a Perl module residing in~/OnePop
:$ PERL5LIB=~/OnePop prove -l t ... PERL5LIB is unset here ....When a command is preceded by a variable assignment like this, the shell sets and exports the variable (
PERL5LIB
) to that command, but after that the variable will be unset again. You can also set the variable in the shell, so that all subsequent commands will inherit it.$ export PERL5LIB=~/OnePop ... $ prove -l t ... PERL5LIB continues to be set here ...If you forget the
export
keyword in the above example (i.e. assigns the value usingPERL5LIB=~/OnePop
on a separate line) the variable will be set in the shell, but it will not be inherited by any commands you run (meaning thatprove
will not be able to see it).Finally, if you wanted to set the environment
PERL5LIB
variable from inside a Perl program you'd have to write it like this:$ENV{PERL5LIB} = glob("~/OnePop"); # glob() expands the tilde system(qw( prove -l t ));Though, as other have pointed out, if you want to specify the include path from inside Perl it is easier/better to use
use lib $PATH
. share improve this answer follow answered May 20 '14 at 11:05 zrajm 1,149 1 1 gold badge 11 11 silver badges 18 18 bronze badges> ,
add a commentbot403 , 2011-03-02 14:44:36
0PERL5INC is an environment variable. Environment variables are only inherited from parents to their children and can't (easily) be set the other way around. If you want to store extra search paths in an external file I suggest you make it a simple list of paths and write a simple loop to read each path from the file and manipulate @INC in the current process. If you want this to be done early at compile time you'll have to use a BEGIN {} block.
For example
BEGIN{ open(INCFILE,"<","my.inc.file") or die($!); foreach(<INCFILE>){ push @INC,$_; } close(INCFILE); }share improve this answer follow edited Mar 27 '17 at 11:00 Donal Fellows 115k 17 17 gold badges 126 126 silver badges 190 190 bronze badges answered Mar 2 '11 at 14:44 bot403 1,923 13 13 silver badges 14 14 bronze badges> ,
add a comment> ,
0 Alternative to PERL5LIB:You could instead install the latest version of Perl 5 available (in a non-system location, of course). After you have used a module file or done whatever is necessary to make the new
perl
andcpan
executables visible to your shell, you can usecpan
to install all the modules you need. I have sometimes done this for individual applications in a similar vein to using Python Virtual Environments.
Jan 01, 2013 | stackoverflow.com
Evan Carroll , 2013-06-04 20:37:24
63 5I just installed Perl 5.18, and I get a lot of warnings like this,
given is experimental at .\[...].pl line [...]. when is experimental at .\[...].pl line [...]. Smartmatch is experimental at C:/strawberry/perl/site/lib/[...] line [...].Looking into these warnings -- which I've never heard mentioned anywhere -- I was only able to find this in two places,
- perldelta for 5.18 , which only really mentions insofar as to say that the feature has been downgraded to experimental ?
- this nntp.perl.org post
The Perl Delta still does the most to give mention as to what's happening with those features, it's halfway down buried in the pod,
Smart match, added in v5.10.0 and significantly revised in v5.10.1, has been a regular point of complaint. Although there are a number of ways in which it is useful, it has also proven problematic and confusing for both users and implementors of Perl. There have been a number of proposals on how to best address the problem. It is clear that smartmatch is almost certainly either going to change or go away in the future. Relying on its current behavior is not recommended. Warnings will now be issued when the parser sees ~~, given, or when.
I'm confused at how the most significant change in Perl in the past 10 years could be pulled. I've started using
given
,when
, andsmartmatch
all over the place. Is there any more information about these futures? How is anyone finding them "confusing?" How are these features likely to change? Is there a plan to implement these features with a module? perl smartmatch share improve this question follow edited Aug 23 at 19:21 HoldOffHunger 7,890 4 4 gold badges 44 44 silver badges 85 85 bronze badges asked Jun 4 '13 at 20:37 Evan Carroll 59.4k 37 37 gold badges 193 193 silver badges 316 316 bronze badgesikegami ,
Wrong file. You have 5.18, so read the perldelta for 5.18. metacpan.org/module/RJBS/perl-5.18.0/pod/ domm.plix.at/perl/2013_05_given_smartmatch.html – daxim Jun 4 '13 at 20:40ikegami ,
37There are problems with the design of smart-matching. The decision of what any given
TYPE ~~ TYPE
should do is most often unobvious, inconsistent and/or disputed. The idea isn't to remove smart matching; it's to fix it.Specifically,
~~
will be greatly simplified, as you can see in a proposal by the 5.18 pumpking. Decisions as to how two things should match will be done with helpers such as those that already exist in Smart::Match .... ~~ any(...)Much more readable, much more flexible (fully extensible), and solves a number of problems (such as "When should X be considered a number, and when should it be considered a string?"). share improve this answer follow edited Jul 3 '13 at 20:23 answered Jun 5 '13 at 2:25 ikegami 308k 14 14 gold badges 212 212 silver badges 451 451 bronze badges
Joel Berger ,
Wow, I hadn't seen Smart::Match! This is aweome! leont++ – Joel Berger Jun 5 '13 at 2:42Joel Berger , 2013-06-05 03:19:07
21Some insights might be gained by reading rjbs's proposed changes to smartmatch . He is the pumpking (Perl release manager) after all, so his comments and his view of the future is more relevant than most. There is also plenty of community comment on the matter, see here for instance. The 'experimental' status is in effect because, since things are likely to change in the future, it is responsible to inform users of that fact, even if we don't know what those changes will be. share improve this answer follow edited Jun 5 '13 at 3:40 answered Jun 5 '13 at 3:19 Joel Berger 19.5k 4 4 gold badges 45 45 silver badges 99 99 bronze badges
> ,
add a commentraina77ow ,
9Well, that's what's said in the description of the patch that downgraded this set of features to experimental:
The behavior of given/when/~~ are likely to change in perl 5.20.0: either smart match will be removed or stripped down. In light of this, users of these features should be warned. A category "experimental::smartmatch" warning should be issued for these features when they are used.
So whil you can indeed turn these warnings off, with something like this ( source ):
no if $] >= 5.018, warnings => "experimental::smartmatch";... it's just turning your eyes off the problem. share improve this answer follow answered Jun 4 '13 at 20:43 raina77ow 86.7k 10 10 gold badges 171 171 silver badges 201 201 bronze badges
tjd ,
It's not about how to turn these warnings off, it's about what's wrong with Smartmatch/given/when and how will they be remedying the problem. The roadmap is just "change ahead" with no certainty of direction. – Evan Carroll Jun 4 '13 at 20:48
Oct 01, 2020 | ldami.blogspot.com
Monday, June 23, 2014 Perl smartmatch : what now ? Sorry to wake up an old discussion, but ... does anybody have a clear idea of what is going to happen to smartmatch ?
Our team maintains dozens of internal applications and modules containing "given/when" and smartmatch statements. Most of this code was written between 2007 and 2012 -- remember, at that time smartmatch was an official feature, never mentioned as being "experimental", so we happily used it in many places. The reasons for using smartmatch were quite modest :
- match a scalar against an array
- match 2 scalars, without a warning when one of the scalars is undef
- more readable switch statements, thanks to "given/when"
- When 5.18 came out, I was quite worried about the regression of smartmatch to "experimental" status, but I was confident that things would be settled in 5.20, so I decided not to upgrade (we still use 5.14). Now 5.20 is out .. and nothing has changed about smartmatch, without even a clue about how this is going to evolve.
Our servers cannot easily upgrade to 5.20, because this would throw warnings all over the place. I tried to find a way to globally turn off these warnings (like set PERL5OPT=-M-warnings=experimental::smartmatch, or PERL5OPT=-M= experimental::smartmatch ), but this doesn't work because the "no warnings" pragma is lexically scoped, so global settings are not taken into account.
So my options are :
- don't change anything, don't upgrade, and wait for 5.22, hoping that some reasonable form of smartmatch will be reintroduced into the core
- revise all source files, adding a line "use experimental qw/smartmatch/;" at the beginning of each lexical scope ... but I have no guarantee that this will still work in future versions
- revise all source files, removing the given/when/smartmatch statements and replacing them with plain old Perl, or with features from some CPAN modules like match::smart or Smart::Match ... but it would be a pity to engage in such work if regular smartmatch comes back in a future version of Perl.
- As you can see, none of these options is really satisfactory, so I would be interested in hearing if other companies are in the same situation and how they decided to handle it.
By the way, I love the new Perl way of introducing new features as "experimental", until they become stable and official ... but this only works well when the experimental status is declared from the start . The problem with smartmatch is that it had been official for several years, before being retrograted to experimental. Agreed, the full semantics of smartmatch as published in 10.0 had inconsistencies, but throwing away the whole thing is a bit too harsh -- I'm sure that many users like me would be happy with a reasonable subset of rules for matching common cases.
Thanks in advance, Laurent Dami Posted by dami at 9:07 PM13 comments:- Aaron Priven June 24, 2014 at 12:07 AM
I think this might be a good question to pose on the perl5porters mailing list.
Reply- LeoNerd June 24, 2014 at 2:55 PM
You might also like Switch::Plain
Reply- Unknown June 24, 2014 at 5:32 PM
yes, I totally cann't accept this change as a common user!
Reply- Ed Avis June 24, 2014 at 7:13 PM
I changed my code from
if ($x ~~ @a)
to
use List::AllUtils qw(any);
Reply Replies
if (any { $_ eq $x } @a)- Unknown June 30, 2014 at 2:55 PM
Why should I use List::AllUtils=any for this case?
Is it better than `if (grep { $_ eq $x } @a )` ?
- Anonymous June 30, 2014 at 5:01 PM
grep will always iterate through the entire list given. any will stop as soon as it finds a single element matching the condition, which means on average it only has to iterate through half the elements.
- Unknown July 1, 2014 at 11:14 AM
Thanks!
- Unknown July 1, 2014 at 11:16 AM
But I can't find it in docs. Sources clarify this.
- Reply
- Aaron Priven June 24, 2014 at 8:10 PM
Thanks LeoNerd. Switch::Plain is very cool, as are lots of other things on https://metacpan.org/author/MAUKE ...
Reply- Anonymous June 27, 2014 at 12:15 PM
Hey, I'm in the same boat, I've been using smartmatch for switch since appearance and I like it, it works for me. The way i deal with pragmas is that i centralize them in a custom minipackage, as in "package pragmas" and I import that, so it's easier to manage "slight incompatibilities" like these. So when p5p marked it as experimental and issued a warning for it, i just put warnings->unimport( 'experimental::smartmatch' ) if $] >= 5.018; right below the "usual" warnings->import( FATAL => 'all' ); If p5p will would rip it off entirely, I'll just fetch some variant from cpan, put it in the pragmas package and import it from there, transparently. It's annoying, but it's not p5p's responsibility to update my code, if I wanna keep up with all the goodies and advancements. Otherwise you keep the code "dead", stuck on 5.14 and that's that, it works.
Reply- Anonymous July 1, 2014 at 11:16 AM
Hi we had the same issue with pseudhashes which was an official feature until 5.10
The problem was that old systems had huge databases with old storables containing pseudohashes. there was no wayI had to write a module to serialize pseudohashes structures into plain hashes, and we then saved as hashed structured when they appreared.
Or just leave them unitl all nodes in a cluster was uploaded from the perl 5.8.9.You have to live with it, just write software that adopts.
Reply- Unknown August 27, 2015 at 4:39 PM
Hello, I may be ressurect an old post, but as written here ( http://perldoc.perl.org/perl5180delta.html#The-smartmatch-family-of-features-are-now-experimental ), it is possible to stop the warning with this command:
no if $] >= 5.018, warnings => "experimental::smartmatch";
This will may be useful for others ^^'.
Reply- LenW September 3, 2015 at 7:59 AM
Well, 5.22 is out. Has ANYTHING happened in this area?
Reply
Does anyone know how to suppress the warnings globally
(eg with an envar) ?
Feb 22, 2018 | www.perl.com
P5P update: Smarter Match
This post will be part of a new communication channel between p5p and the community. We hope to share more with you and keep you up-to-date using this platform.
On December 20th, 2017, we released Perl 5.27.7, which included a massive change to smartmatch . Since then it has been reverted. What happened?
Smartmatch has a long history. It was introduced in 5.10 back in December 2007 and significantly revised in 5.10.1. It was a good idea, but ended up causing more harm than good to the point it was deemed unreliable.
In an unprecedented step, it was marked as "experimental" in Perl 5.18.0, released in May 2013. Here is the mention of this in perldelta :
Smartmatch, added in v5.10.0 and significantly revised in v5.10.1, has been a regular point of complaint. Although there are some ways in which it is useful, it has also proven problematic and confusing for both users and implementors of Perl. There have been some proposals on how to best address the problem. It is clear that smartmatch is almost certainly either going to change or go away in the future. Relying on its current behavior is not recommended.
Warnings will now be issued when the parser sees
~~
,given
, orwhen
.Since then, various threads were raised on how to resolve it. The decided approach was to simplify the syntax considerably. It took several rounds of discussions (with some bike-shedding) to settle what to simplify and to reach an agreement on the new behavior.
Last year we had finally reached an agreement on the significant perspectives. The changes were implemented by Zefram, a core developer. The work was published on a public branch for comments.
When no objections were filed, Zefram merged the new branch. It was included in the 5.27.7 development release.
Following the release of this development version, issues started popping up with the effect this change made. A fair portion of CPAN was breaking to the point that one of the dedicated Perl testers decided it was unfeasible for them to continue testing. Subsequently, we decided to revert this change.
What went wrong?First of all, it was clear that moving smartmatch to experimental did not achieve what we had hoped. Features are marked as experimental to allow us to freely (for some value of "freely") adjust and tinker with them until we are comfortable making them stable. The policy is that any experimental feature can be declared stable after two releases with no behavioral change. With smartmatch, it was marked after numerous versions in which it existed as a stable feature.
Secondly, the change was massive. This in and of itself is not necessarily wrong, but how we handled it leaves room for improvement.
Thirdly, centering the communication around this change on the core mailing list was insufficient to receive enough feedback and eyes on the problem and the proposed solution. We should have published it off the list and sought more input and comments. We hope to use this platform to accomplish that.
Fourthly, we could have asked our dedicated testers for help on running additional, specific tests, to view what would break on CPAN and how damaging this change could be.
Where do we go from here?Despite not being the best way to learn from a mistake, there was minimal damage. The new syntax and behavior were only available on a single development release, did not reach any production code, and was reverted within that single release.
To address smartmatch again, we will need to reflect upon our mistakes and consider approaching it again by communicating the change better and by receiving additional feedback to both offer a useful feature and pleasing syntax. This will take time, and we are not rushing to revisit smartmatch at the moment.
We apologize for the scare and we appreciate the quick responses to resolve this situation. Thank you.
Oct 30, 2014 | perlmaven.com
When a Perl script is executed the user can pass arguments on the command line in various ways. For example perl program.pl file1.txt file2.txt or perl program.pl from-address to-address file1.txt file2.txt or, the most common and most useful way:
perl program.pl -vd --from from-address --to to-address file1.txt file2.txtHow can we deal with this information?
When the scripts starts to run, Perl will automatically create an array called @ARGV and put all the values on the command line separated by spaces in that variable. It won't include perl and it won't include the name of our script ( program.pl in our case), that will be placed in the $0 variable. @ARGV will only include the values located after the name of the script.
In the above case @ARGV will contain: ('-vd', '--from', 'from-address', '--to', 'to-address', 'file1.txt', 'file2.txt')
We can access @ARGV manually as described in the article about @ARGV , but there are a number of modules that will handle most of the work for you. In this article we'll see Getopt::Long a module that also comes with the standard installation of Perl.
Explain the command lineJust before doing that, let's see what is really our expectation from the command line processing.
- Long names with values: we would like to be able to accept parameters with long names followed by a value. For example --to VALUE . ("Long" is relative here, it just means more than 1 character.)
- Long names without value: We would like to accept flags that by their mere existence will turn some flag on. For example --verbose .
- Short names (or single-character names) with or without values. The above two just written -t VALUE and -v .
- Combining short names: -vd should be understood as -v -d . So we want to be able to differentiate between "long names" and "multiple short names combined". The difference here is that "long names" start with double-dash -- while short names, even if several of them were combined together start with a single dash - .
- Non-affiliated values, values that don't have any name starting with a dash in front of them. For example file1.txt file2.txt .
There can be lots of other requirements and Getopt::Long can handle quite a few of them, but we'll focus on the basics.
Getopt::LongGetopt::Long exports a function called GetOptions , that can process the content of @ARGV based on the configuration we give to it. It returns true or false indicating if the processing was successful or not. During processing it removes the items from @ARGV that have been successfully recognized. We'll take a look at possible errors later on. For now, let' see a small example we save in cli.pl :
- use strict ;
- use warnings ;
- use 5.010 ;
- use Getopt :: Long qw ( GetOptions );
- my $source_address ;
- GetOptions ( 'from=s' => \$source_address ) or die "Usage: $0 --from NAME\n" ;
- if ( $source_address ) {
- say $source_address ;
- }
After loading the module we declare a variable called $source_address where the value of the --from command line flag will be stored. We call GetOptions with key-value pairs. The keys (in this case one key) is the description of the flag. In this case the from=s declares that we are expecting a command line parameter called --from with a string after it. Because in Perl numbers can also be seen as strings, this basically means "pass me any value". This declaration is then mapped to the variable we declared earlier. In case the syntax is unclear => is a "fat arrow" you might be familiar from hashes and the back-slash \ in-front of the variable indicates that we are passing a reference to the variable. You don't need to understand references in order understand this code. Just remember that the variables on the right hand side of the "fat comma" operators need to have a back-slash when calling GetOptions .
We can run this program in several ways: perl cli.pl --from Foo will print "Foo". The value passed after the -from flag is assigned to the $source_address variable. On the other hand running perl cli.pl will not print anything as we have no passed any value.
If we run it perl cli.pl Foo it won't print anything either, as GetOptions only deals with options that start with a dash ( - ). (This is actually configurable, but let's not get there now.)
FailuresSo when will the short circuit or die kick-in?
Unknown optionIf we run the script passing something that looks like a parameter name, but which has not been declared when calling GetOptions . Something that starts with a dash - . For example:
perl cli.pl --to Bar
Unknown option: to Usage: cli.pl --from NAMEThe first line is a warning printed by GetOptions , the second line is the string we generated using die .
Option requires an argumentAnother case is when we run the script, pass --from , but without passing any value after it:
perl cli.pl --from
In that case the output will look like this:
Option from requires an argument Usage: cli.pl --from NAMEHere too, the first line was from GetOptions and the second line from our call to die . When we called GetOptions we explicitly said =s that we are expecting a string after the --from .
Default valuesOften we would like to give a default value to one of the options. For example in the case of the --from field we might want it to default to the word 'Maven'. We can do it by assigning this value to the $source_address variable before calling GetOptions . For example, at the time we declare it using my .
- my $source_address = 'Maven' ;
- GetOptions ( 'from=s' => \$source_address ) or die "Usage: $0 --from NAME\n" ;
- if ( $source_address ) {
- say $source_address ;
- }
If the user does not pass the --from flag then GetOptions will not modify the value in the $source_address variable. Running perl cli.pl will result in "Maven".
Flags without valueIn addition to parameters that require a value, we also would like to allow flags. Names, that by their presence make a difference. These things are used when we want to allow the users to turn on debugging, or to set the verbosity of the script.
- use strict ;
- use warnings ;
- use 5.010 ;
- use Getopt :: Long qw ( GetOptions );
- my $debug ;
- GetOptions ( 'debug' => \$debug ) or die "Usage: $0 --debug\n" ;
- say $debug ? 'debug' : 'no debug' ;
Originally the $debug variable contained undef which is considered to be false in Perl. If the user passes the --debug flag, the corresponding variable will be set to some true value. (I think it is the number one, but we should only rely on the fact that it evaluates to true.) We then use the ternary operator to decide what to print.
The various ways we call it and the output they produce:
$ perl cli.pl no debug $ perl cli.pl --debug debug $ perl cli.pl --debug hello debugThe last example shows that values placed after such name are disregarded.
Multiple flagsObviously, in most of the scripts you will need to handle more than one flag. In those cases we still call GetOptions once and provide it with all the parameters:
Combining the above two cases together we can have a larger example:
- use strict ;
- use warnings ;
- use 5.010 ;
- use Getopt :: Long qw ( GetOptions );
- my $debug ;
- my $source_address = 'Maven' ;
- GetOptions (
- 'from=s' => \$source_address ,
- 'debug' => \$debug ,
- ) or die "Usage: $0 --debug --from NAME\n" ;
- say $debug ? 'debug' : 'no debug' ;
- if ( $source_address ) {
- say $source_address ;
- }
Running without any parameter will leave $debug as undef and the $source_address as 'Maven':
$ perl cli.pl no debug MavenPassing --debug will set $debug to true, but will leave $source_address as 'Maven':
$ perl cli.pl --debug debug MavenPassing --from Foo will set the $source_address but leave $debug as undef :
$ perl cli.pl --from Foo no debug FooIf we provide parameters, they will both set the respective variables:
$ perl cli.pl --debug --from Foo debug FooThe order of the parameters on the command line does not matter:
$ perl cli.pl --from Foo --debug debug FooShort namesGetopt::Long automatically handles shortening of the option names up to ambiguity. We can run the above script in the following manner:
$ perl cli.pl --fr Foo --deb debug FooWe can even shorten the names to a single character:
$ perl cli.pl --f Foo --d debug Fooand in that case we can even use single-dash - prefixes:
$ perl files/cli.pl -f Foo -d debug FooThese however are not really single-character options, and as they are they cannot be combined:
$ perl cli.pl -df Foo Unknown option: df Usage: cli.pl --debug --from NAMESingle-character optionsIn order to combine them we need two do two things. First, we need to declare the options as real single-character options. We can do this by providing alternate, single-character names in the definition of the options:
- GetOptions (
- 'from|f=s' => \$source_address ,
- 'debug|d' => \$debug ,
- ) or die "Usage: $0 --debug --from NAME\n" ;
The second thing is that we need to enable the gnu_getopt configuration option of Getopt::Long by calling Getopt::Long::Configure qw(gnu_getopt);
- use Getopt :: Long qw ( GetOptions );
- Getopt :: Long :: Configure qw ( gnu_getopt );
After doing that we can now run
$ perl cli.pl -df Foo debug FooThe full version of the script with the above changes looks like this:
Non-affiliated values
- use strict ;
- use warnings ;
- use 5.010 ;
- use Getopt :: Long qw ( GetOptions );
- Getopt :: Long :: Configure qw ( gnu_getopt );
- use Data :: Dumper ;
- my $debug ;
- my $source_address = 'Maven' ;
- GetOptions (
- 'from|f=s' => \$source_address ,
- 'debug|d' => \$debug ,
- ) or die "Usage: $0 --debug --from NAME\n" ;
- say $debug ? 'debug' : 'no debug' ;
- if ( $source_address ) {
- say $source_address ;
- }
The GetOptions function only handles the parameters that start with a dash and their corresponding values, when they are relevant. Once it processed the options it will remove them from @ARGV . (Both the option name and the option value will be removed.) Any other, non-affiliated values on the command line will stay in @ARGV . Hence if we add Data::Dumper to our script and use that to print the content of @ARGV at the end ( print Dumper \@ARGV ) as in this script:
- use strict ;
- use warnings ;
- use 5.010 ;
- use Getopt :: Long qw ( GetOptions );
- use Data :: Dumper ;
- my $debug ;
- my $source_address = 'Maven' ;
- GetOptions (
- 'from=s' => \$source_address ,
- 'debug' => \$debug ,
- ) or die "Usage: $0 --debug --from NAME\n" ;
- say $debug ? 'debug' : 'no debug' ;
- if ( $source_address ) {
- say $source_address ;
- }
- print Dumper \@ARGV ;
We get the following results:
$ perl files/cli.pl -f Foo -d file1.txt file2.txt debug Foo $VAR1 = [ 'file1.txt', 'file2.txt' ];After processing the options, file1.txt and file2.txt were left in @ARGV . We can now do whatever we want with them, for example we can iterate over the @ARGV array using foreach .
AdvancedGetopt::Long has tons of other options. You might want to check out the documentation.
There are also other solutions, for example if you are using Moo for light-weight object oriented programming, you could take a look at MooX::Options explained in a number of advanced articles: for example Switching to Moo - adding command line parameters and Writing Command line scripts and accepting command line parameters using Moo .
Sep 30, 2020 | perlmonks.org
Re^6: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 27, 2020 at 22:37 UTCWe need not "assume that somebody uses this formatting". I do it frequently, and I have often seen it in other people's code. That fact that you use it and saw it in other people code means nothing. People often adopt and use bad programming style. Even talented programmers do. Look at classic The Elements of Programming Style , by Brian W. Kernighan and P. J. Plauger. They include such recommendations as ( cited from https://en.wikipedia.org/wiki/The_Elements_of_Programming_Style ) :
- Write clearly -- don't be too clever.
- Say what you mean, simply and directly.
- ... ... ...
- Write clearly -- don't sacrifice clarity for efficiency.
- ... ... ...
- Parenthesize to avoid ambiguity.
- ... ... ...
- Make sure special cases are truly special.
- ... ... ...
The real question is whether the use you advocate represents a good Perl programming style or not.
I would understand the use of post-fix if construct in a loop to specify exit condition. Something like:
return if ($exit_condition);They make code more readable in comparison with the regular if statement as as such have certain value and IMHO represent a good programming style.In many other cases the desire to save two curly braces looks to me a very questionable practice and a bad programming style. Your mileage may vary.
Sep 29, 2020 | perlmonks.org
likbez on Sep 29, 2020 at 18:01 UTC
Re^11: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staffby likbez on Sep 29, 2020 at 18:01 UTC
If I have to maintain (as only maintainer) a piece of perl code, I will *rewrite* *all* statements as you state from action if expression; to expression and action; as that (to me) is waaaaaaaaaay easier to read/understand/maintain. Nothing to do with "idiomatic perl". Nothing at all!People are extremely flexible. The same is true for programmers. Many of talented programmers I encountered have a somewhat idiosyncratic style...In your private role you are free to do whatever you wish. After all programming open source is about fun, not so much about discipline.
The situation radically changes in commercial projects. If you are a manager of a large project you need to ensure a uniform and preferably simple style via guidelines that explicitly prohibit such "excesses" and to step on the throat of such "excessively creative" people to make them "behave".
That's why languages that allow too much syntactic freedom are generally not welcomed in large commercial projects, even if they are able to manage large namespaces more or less OK.
Let's be frank: Perl lost Web applications development more or less completely. The reasons are not clear and can be argued, but the fact is indisputable. But the problem that I see is that Perl can lose attraction among sysadmins because of excessive push of OO programming style by OO-fanatics and the second rate book authors, as well as due to inability of distribute remaining scarce development resources toward modest and not fancy (unlike closures, accessors, frameworks and other fancy staff) improvements in the procedural programming arena (the area which this post is all about).
An interesting question is: at what point excessive syntactic flexibility stimulates perverted programming style which is reflected in the derogative term "complexity junkies"? When in the program simple things look complex, and complex unmanageable. "Object oriented spaghetti" ('Lasagna code' with too many layers) is another term that addresses the same problem. See, for example, discussion at https://medium.com/better-programming/is-object-oriented-programming-garbage-66c4f41adcaa
Also https://www.youtube.com/watch?time_continue=9&v=V6VP-2aIcSc&feature=emb_logo
Sep 14, 2020 | www.reddit.com
Three things occur to me that could help Perl.At least in the US all other things being equal there is a tendency to root for the underdog in any given conflict. Python is seen as king. Perl is seen as an "old man's language." Never mind the two languages are contemporaries and Perl that follows best practices isn't difficult to follow.
My first thought its we can probably leverage the psychological tendency to root for the underdog as means to promote the language. Let's talk about that. Am I right? Am I wrong?
Second, it seems that there are very few Code Academy type sites that support and promote Perl as a language worth learning. I keep hearing about the need for "fresh blood." Well, I'm "fresh blood" but I used books from Amazon to get where I'm at. I'm still in the process of learning. It seems most younger developers just want to go from one structured tutorial to another without buying a print or even Kindle book.
So, how do we promote Perl to such sites? That's a major bottle neck, I think. Sure, Python dominates but there is space for Rust and Go devops. I see space for Perl at the table too.
Third, there are lots of small to medium sized projects that happen to be written in Perl that don't get a lot of visibility. Sure, they're (probably) on CPAN, but we can't all know everything.
Someone made a point to me in another post that programming languages are like gods in some fantasy literature: they lose power as others stop believing in them. Point taken. So, let's increase the number of devotees by talking about these projects and their usefulness.
What are some cool projects out there that leverage the best of Perl that don't get the visibility they deserve? Yes, you can plug your own project and/or talk about its challenges.
level 1vvelox 8 points· 3 days ago
· edited 3 days ago
ncps - A handy colorized(optional) ps like utility that with search options. Also can be told to display memory/CPU summary for all matched procs.
ncnetstat - A handy colorized(optional) netstat like utility that with search options. Among other interesting features, can be told to display CPU and memory usage for process that has the connection.
piddler - Grab info from the proc table for a single PID and display it and all open files and network connections.
essearcher - A handy command line utility for searching elasticsearch and displaying the results in a nicely formatted manner. Can even me used as a nagios check. Comes with support for fail2ban, HTTP access logs, Postfix, and syslog out of the box.
Net::DHCP::Windows::Netsh::Parse - Really helps for converting Windows DHCP servers over to ISC DHCPd.
inidhcp - Helps for managing DHCP subnets... adding new ones, checking for overlap, some basic sanity checking, and generation.... I use it to basically help manage PXE boot subnets.
level 1 relishketchup 5 points· 3 days ago· edited 3 days agovvelox 4 points· 3 days agoPaws is another great example of modern tools which allows you to use Perlish code (instead of Boto3 in Python) for AWS
Rex is an Ansible-like automation tool written in Perl
Rex is an Ansible-like automation tool written in Perl
I love rex. So much more friendly than ansible and so bloody flexible. erkiferenc 3 points· 2 days ago
Rex is cool, but no one is adopting it over Ansible/Salt/Puppet/etc.
As Rex maintainer, I feel the words "no one" to be too strong in this context, so let me clarify that claim a bit :)
I agree that the market share is relatively low. Partly because it's a volunteers-only project, and I'm currently not aware of anybody actively flooding the advertisement channels with Rex content in their free time (and for free). Anybody willing to change that, please go ahead!
Another factor for relatively low visibility is that the purpose of Rex, as a framework, is to allow one to build their own automation tool required to solve their own needs. This means most of the Rex-based solutions are custom-made. So it's often too specific for their own situation, or they don't have the permissions to publish it.
Personally, I have more first-hand experience with use cases where Rex is used right form the start. Based on community reports, it's also fairly common that one of the alternatives are replaced with Rex at some point. Overall there are known use cases ranging from one-man shows to tens of thousands of servers.
I guess we gotta put up a success stories page or similar to the website to give those cases more visibility :) Until then, please feel free to blog about it, tweet about it, give a talk at the next event, star it on GitHub, favorite it on MetaCPAN, vote on StackShare...or even hire/sponsor me to do it all! :D
level 1 DerBronco 9 points· 3 days agoI am living in a 25k town with no metropolitan area within 200km.
My client is a leading importer and big wholesaler with a big shipping warehouse.
Our backoffice runs in perl. The warehouse in/out is perl/mariadb.
There are dozens of retailers and dropshippers connected to our db, some pushing, some csv/xml-generators, OpenTrans, shopify, even Lexware-odbc based stuff.
All of it individual code in perl. And not even hip modern perl, but rather oldschool stuff, only few cpan modules etc
that makes me indespensable. There are simply no perl coders in the wider area. It wouldnt even make sense to train somebody in perl AND my codebase thats been growing since 2003 because that will take years.
And thats why im staying with perl.
TLDR: using underdog coding language will make my living and pay my bills till retirement.
Lets it be the underdog please ;) hurricup 1 point· 2 days ago
Perl now have a full featured IDE with IntelliJ IDEA and perl plugin: https://github.com/Camelcade/Perl5-IDEA
level 1 szabgab 0 points· 19 hours ago· edited 19 hours agoIf I may, I'd like to challenge you asking why would you like to promote Perl and Perl-based projects?
I think in order for this to be successful you need to formulate an answer to that question.
I know why would it be great for me, but:
What do you gain from Perl being more popular? What do others gain from it? Who has interest in it? Who has the energy and time to invest in this effort? Who might have money to financially support Perl-related promotional or development efforts?
Sep 12, 2020 | perlmonks.org
likbez on Sep 10, 2020 at 20:41 UTC
Re^2: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 10, 2020 at 20:41 UTC Reputation: -11Why would this be highly desirable? Consider: print( "Hello World" ) if( 1 ); [download] versusI do not understand your train of thought. In the first example end of the line occurred when all brackets are balanced, so it will will be interpretered as print( "Hello World" ); if( 1 ); [download]print( "Hello World" ) if( 1 < 2 ) { print("Goodbye"); };So this is a syntactically incorrect example, as it should be. The second example will be interpreted as
print( "Hello World" ); if( 1 < 2 ) { print("Goodbye"); };Anonymous Monk on Sep 10, 2020 at 20:51 UTC
Re^3: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by Anonymous Monk on Sep 10, 2020 at 20:51 UTC So this is a syntactically incorrect example, as it should be.wrong. print "Hello World" if 1; is valid Perl
likbez on Sep 10, 2020 at 21:28 UTC
Re^4: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 10, 2020 at 21:28 UTCThat supports another critique of the same proposal -- it might break old Perl 5 scripts and should be implemented only as optional pragma. Useful only for programmers who experience this problem.
Because even the fact that this error is universal and occurs to all programmers is disputed here.
dsheroh on Sep 11, 2020 at 08:11 UTC
Re^5: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dsheroh on Sep 11, 2020 at 08:11 UTCjohngg on Sep 12, 2020 at 13:46 UTC
Re^5: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by johngg on Sep 12, 2020 at 13:46 UTCif we assume that somebody uses this formatting to suffix conditionalsI do, pretty much all the time! The ability to span a statement over multiple lines without jumping through backslash hoops is one of the things that makes Perl so attractive. I also think it makes code much easier to read rather than having excessively long lines that involve either horizontal scrolling or line wrapping. As to your comment regarding excessive length identifiers, I come from a Fortran IV background where we had a maximum of 8 characters for identifiers (ICL 1900 Fortran compiler) so I'm all for long, descriptive and unambiguous identifiers that aid those who come after in understanding my code.
Cheers,JohnGG
likbez on Sep 10, 2020 at 15:38 UTC
Re^2: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 10, 2020 at 15:38 UTC Reputation: -14Because people have a natural tendency to omit them at the end of the line. That's why.
This is an interesting psychological phenomenon that does not depend on your level of mastery of the language and is not limited to novices.
dave_the_m on Sep 10, 2020 at 18:09 UTC
Re^3: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dave_the_m on Sep 10, 2020 at 18:09 UTCDave.
likbez on Sep 10, 2020 at 20:56 UTC
Re^4: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 10, 2020 at 20:56 UTCCan you please tell us how many times you corrected the missing semicolon error in your scripts during the last week?
dave_the_m on Sep 11, 2020 at 10:37 UTC
Re^5: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dave_the_m on Sep 11, 2020 at 10:37 UTC $a = $b + $c + $d + $e; [download] If not, what are the exact criteria for things on the next line to trigger or not a semicolon?Dave.
likbez on Sep 11, 2020 at 14:20 UTC
Re^6: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 11, 2020 at 14:20 UTCIn the following, the first line has a balance of brackets and looks syntactically correct. Would you expect the lexer to add a semicolon?Yes, and the user will get an error. This is similar to previous example with trailing on a new line "if (1);" suffix. The first question is why he/she wants to format the code this way if he/she suffers from this problem, wants to avoid missing semicolon error and, supposedly enabled pragma "softsemicolons" for that?$a = $b + $c + $d + $e;This is the case where the user need to use #\ to inform the scanner about his choice. But you are right in a sense that it creates a new type of errors -- "missing continuation." And that there is no free lunch. This approach requires specific discipline to formatting your code.
dave_the_m on Sep 11, 2020 at 14:52 UTC
Re^7: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dave_the_m on Sep 11, 2020 at 14:52 UTCThe reason I gave that code as an example is that it's a perfectly normal way of spreading complex expressions over multiple lines: e.g. where you need to add several variables together and the variables have non-trivial (i.e. long) names, e.g.
$pressure = $partial_pressure_nitrogen + $partial_pressure_oxygen + $partial_pressure_water_vapour + $partial_pressure_argon + $partial_pressure_carbon_dioxide;[download] In this case, the automatic semicolons are unhelpful and will give rise to confusing error messages. So you've just switched one problem for another, and raised the cognitive load - people now need to know about your pragma and also know when its in scope.Dave.
likbez on Sep 11, 2020 at 16:51 UTC
Re^8: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 11, 2020 at 16:51 UTCYes it discourages certain formatting style. So what ? If you can't live without such formatting (many can) do not use this pragma. BTW you can always use extra parentheses, which will be eliminated by the parser as in
$pressure = ( $partial_pressure_nitrogen + $partial_pressure_oxygen + $partial_pressure_water_vapour + $partial_pressure_argon + $partial_pressure_carbon_dioxide );dave_the_m on Sep 11, 2020 at 17:05 UTC
Re^9: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dave_the_m on Sep 11, 2020 at 17:05 UTC* How exactly does the lexer/parser know when it should insert a soft semicolon?
* How exactly does it give a meaningful error message when it inserts one where the user didn't intend for there to be one?
My problem with your proposal is that it seems to require the parser to apply some complex heuristics to determine when to insert and when to complain meaningfully. It is not obvious to me what these heuristics should be. My suspicion is that such an implementation will just add to perl's already colourful collection of edge cases, and just confuse both beginner and expert alike.
Bear in mind that I am one of just a handful of people who actively work on perl's lexer and parser, so I have a good understanding of how it works, and am painfully aware of its many complexities. (And its quite likely that I would end up being the one implementing this.)
Dave.
likbez on Sep 11, 2020 at 18:51 UTC
Re^10: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 11, 2020 at 18:51 UTCThe lexical analyzer is Perl is quite sophisticated due to lexical complexity of the language. So I think it already counts past lexems and thus can determine the balance of "()", '[]' and "{}"
So you probably can initially experiment with the following scheme
If all the following conditions are true
- You reached the EOL
- Pragma "softsemicolon" is on
- The balance is zero
- The next symbol via look-ahead buffer is not one of the set "{", "}", ';', and ".", -- no Perl statement can start with the dot. Probably this set can be extended with "&&", '||', and "!". Also the last ',' on the current line, and some other symbols clearly pointing toward extension of the statement on the next line should block this insertion.
the lexical analyzer needs to insert lexem "semicolon" in the stream of lexem passed to syntax analyzer.
The warning issued should be something like:
"Attempt to correct missing semicolon was attempted. If this is incorrect please use extra parenthesis or disable pragma "softsemicolon" for this fragment."From what I read, Perl syntax analyser relies on lexical analyser in some unorthodox way, so it might be possible to use "clues" from syntax analyser for improving this scheme. See, for example, the scheme proposed for recursive descent parsers in:Follow set error recovery C Stirling - Software: Practice and Experience, 1985 - Wiley Online Library Some accounts of the recovery scheme mention and make use of non-systematic changes to their recursive descent parsers in order to improve In the former he anticipates the possibility of a missing semicolon whereas in the latter he does not anticipate a missing commadave_the_m on Sep 11, 2020 at 22:02 UTC
Re^11: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dave_the_m on Sep 11, 2020 at 22:02 UTCSo I think it already counts past lexems and thus can determine the balance of "()", '[]' and "{}"It can't currently.If all the following conditions are trueAll of the following satisfy your criteria, are valid and normal perl code, and would get a semicolon incorrectly inserted based on your criteria:use softsemicolon; $x = $a + $b; $x = 1 if $condition; $x = 1 unless $condition1 && $condition2;[download]The warning issued should be something likeI didn't ask what the text of the warning should be, I asked how the parser can determine when the warning should be issued.the scheme proposed for recursive descent parsersBut perl uses an LR(1) parser, not a recursive descent parser.Dave.
likbez on Sep 12, 2020 at 02:06 UTC
Re^12: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 12, 2020 at 02:06 UTCAll of the following satisfy your criteria, are valid and normal Perl code, and would get a semicolon incorrectly inserted based on your criteria:Yes in cases 1 and 2; it depends on depth of look-ahead in case 3. Yes if it is one symbol. No it it is two(no Perl statement can start with && )use softsemicolon; $x = $a + $b; $x = 1 if $condition; $x = 1 unless $condition1 && $condition2;As for "valid and normal" your millage may vary. For people who would want to use this pragma it is definitely not "valid and normal". Both 1 and 2 looks to me like frivolities without any useful meaning or justification. Moreover, case 1 can be rewritten as:
$x =($a + $b);[download] The case 3 actually happens in Perl most often with regular if and here opening bracket is obligatory:if ( ( $tokenstr=~/a\[s\]/ || $tokenstr =~/h\[s\]/ ) && ( $tokenstr... ) ){ .... } [download] Also Python-inspired fascination with eliminating all brackets does not do here any good$a=$b=1; $x=1 if $a==1 && $b=2;[download] should generally be written$a=$b=1; $x=1 if( $a==1 && $b=2);[download]I was surprised that the case without brackets was accepted by the syntax analyser. Because how would you interpret $x=1 if $a{$b}; without brackets is unclear to me. It has dual meaning: should be a syntax error in one case
$x=1 if $a{ $b };[download] and the test for an element of hash $a in another.dave_the_m on Sep 12, 2020 at 06:52 UTC
Re^13: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by dave_the_m on Sep 12, 2020 at 06:52 UTCBoth 1 and 2 looks to me like frivolities without any useful meaning or justificationYou and I have vastly differing perceptions of what constitutes normal perl code. For example there are over 700 examples of the 'postfix if on next line' pattern in the .pm files distributed with the perl core.There doesn't really seem any point in discussing this further. You have failed to convince me, and I am very unlikely to work on this myself or accept such a patch into core.
Dave.
likbez on Sep 12, 2020 at 19:53 UTC
Re^14: What esteemed monks think about changes necessary/desirable in Perl 7 outside of OO staff
by likbez on Sep 12, 2020 at 19:53 UTCYou and I have vastly differing perceptions of what constitutes normal perl code. For example there are over 700 examples of the 'postfix if on next line' pattern in the .pm files distributed with the perl core.Probably yes. I am an adherent of "defensive programming" who is against over-complexity as well as arbitrary formatting (pretty printer is preferable to me to manual formatting of code). Which in this audience unfortunately means that I am a minority.BTW your idea that this pragma (which should be optional) matters for Perl standard library has no connection to reality.
Sep 01, 2020 | www.perl.com
My Perl Wishlist: Invariant Sigils (Part 1)
Oct 27, 2019 by Christopher White
Pop quiz! Q: What was my mistake in this line?
is %HASH{answer}, 'forty-two', '%HASH properly filled';A: I had the answer right, but I messed up the sigil on
HASH
. It should be:is $HASH{answer}, 'forty-two', '%HASH properly filled'; # ^ $, not %Unfortunately, on Perl v5.20+, both statements work the same way! I didn't catch the problem until I shipped this code and cpantesters showed me my mistake. It was an easy fix, but it reminded me that Perl's variant sigils can trip up programmers at any level. If I could change one thing about Perl 5, I would change to invariant sigils.
The current situationIn Perl, the sigil tells you how many things to expect . Scalars such as
$foo
are single values. Any single value in an array@foo
or hash%foo
, since it is only one thing, also uses$
, so$foo
,@foo
, and%foo
could all refer to different pieces of the same variable -- or to different variables. This technique of "variant sigils" works, but confuses new Perl users and tripped up yours truly. To know what you are accessing in an array or hash, you have to look at both the sigil and the brackets. As a reminder:Make the sigils part of the name
Sigil No brackets [ ]
(array access){ }
(hash access)$
$z
: a scalar, i.e., a single value$z[0]
: the first element of array@z
$z{0}
: the value in hash%z
at key"0"
@
@z
: An array, i.e., a list of value(s)@z[0, 1]
: the list($z[0], $z[1])
of two elements from@z
(an "array slice")@z{0, "foo"}
: the list($z{0}, $z{foo})
of two elements from hash%z
%
%z
: A hash, i.e., a list of key/value pair(s)%z[0, 1]
: the list(0, $z[0], 1, $z[1])
of keys and two values from array@z
(a "hash slice")%z{0, "foo"}
: the list("0", $z{0}, "foo", $z{foo})
of keys and values from hash%z
To save myself from repeating my errors, I'd like the sigil to be part of a variable's name. This is not a new idea; scalars work this way in Perl, bash, and Raku ( formerly Perl 6 ). That would make the above table look like:
Sigil No brackets [ ]
(array access){ }
(hash access)$
$z
: a scalar, i.e., a single value$z[0]
: N/A$z{0}
: N/A@
@z
: An array, i.e., a list of value(s)@z[0]
: the first element of@z
@z{0}
: N/A%
%z
: A hash, i.e., a list of key/value pair(s)%z[0]
: N/A%z{0}
: the value in hash%z
at key0
Simpler! Any reference to
But what about slices?@z
would always be doing something with the array named@z
.Slices such as
@z[0,1]
and%z{qw(hello there)}
return multiple values from an array or hash. If sigils@
and%
are no longer available for slicing, we need an alternative. The Perl family currently provides two models: postfix dereferencing ("postderef") syntax and postfix adverbs.Perl v5.20+ support postderef , which gives us one option. Postderef separates the name from the slice:
# Valid Perl v5.20+ $hashref->{a}; # Scalar, element at index "a" of the hash pointed to by $hashref $hashref->@{a}; # List including the "a" element of the hash pointed to by $hashref $hashref->%{a}; # List including the key "a" and the "a" element of the hash pointed to by $hashrefThe type of slice comes after the reference, instead of as a sigil before the reference. With non-references, that idea would give us slice syntax such as
@array@[1,2,3]
or%hash%{a}
.Raku gives us another option: "adverbs" such as
:kv
. For example:# Valid Raku %hash{"a"} # Single value, element at index "a" of %hash %hash{"a"}:v; # The same --- just the value %hash{"a"}:kv; # The list including key "a" and the value of the "a" element of %hashThe adverb (e.g.,
:kv
) goes in postfix position, immediately after the brackets or braces. Following this model, slices would look like@array[1,2,3]:l
or%hash{a}:kv
. (For clarity, I propose:l
, as in l ist, instead of Raku's:v
. Raku's:v
can return a scalar or a list.)So, the choices I see are (postderef-inspired / Raku-inspired):
You can't always get what you want
What you want No subscript [ ]
access{ }
accessScalar $z
: a scalar, i.e., a single value@z[0]
: a single value from an array%z{0}
: the value in hash%z
at key"0"
List of values @z
: an array, i.e., a list of value(s)@z@[0, 1]
/@z[0, 1]:l
: the list currently written($z[0], $z[1])
%z@{0, "foo"}
/%z{0, "foo"}:l
: the list currently written($z{0}, $z{foo})
List of key/value pairs %z
: a hash, i.e., a list of key/value pair(s)@z%[0, 1]
/@z[0, 1]:kv
: the list currently written(0, $z[0], 1, $z[1])
%z%{0, "foo"}
/%z{0, "foo"}:kv
: the list currently written("0", $z{0}, "foo", $z{foo})
I prefer the adverb syntax. It is easy to read, and it draws on all the expertise that has gone into the design of Raku. However, my preference has to be implementable. I'm not convinced that it is without major surgery.
The Perl parser decides how to interpret what is inside the brackets depending on the context provided by the slice. The parser interprets the
...
in@foo[...]
as a list ( ref ). In$foo[...]
, the parser sees the...
as a scalar expression ( ref ). For any slice syntax, the Perl parser needs to know the desired type of result while parsing the subscript expression. The adverb form, unfortunately, leaves the parser guessing until after the subscript is parsed.You can, in fact, hack the Perl parser to save the subscript until it sees a postfix adverb. The parser can then apply the correct context. I wrote a proof-of-concept for
@arr[expr]:v
. It doesn't execute any code, but it does parse a postfix-adverb slice without crashing! However, while writing that code, I ran across a surprise: new syntax isn't tied to ause v5.xx
directive.It turns out the Perl parser lets code written against any Perl version use the latest syntax. Both of the following command lines work on Perl v5.30:
$ perl -Mstrict -Mwarnings -E 'my $z; $z->@* = 10..20' # ^ -E: use all the latest features $ perl -Mstrict -Mwarnings -e 'my $z; $z->@* = 10..20' # (!!!) # ^ -e: not the latest featuresThe second command line does not
use v5.30
, so you can't usesay
(introduced in v5.10). However, you can use postderef (from v5.20)!Because the parser lets old programs use new syntax, any proposed addition to Perl's syntax has to be meaningless in all previous Perl versions. A postfix adverb fails this test. For example, the following is a valid Perl program:
sub kv { "kv" } my @arr = 10..20; print 1 ? @arr[1,2]:kv; # ^^^^^^^^^^^^ valid Perl 5 syntax, but not a slice :( print "\n";My preferred slice syntax could change the meaning of existing programs, so it looks like I can't get my first choice.
Next StepsThis is not the end of the story! In Part 2, I will dig deeper into Perl's parser and tokenizer. I will share some surprises I discovered while investigating postderef. I will then describe a possible path to invariant sigils and the simplicity they can provide.
Sep 01, 2020 | perlmaven.com
How to get a slice of an array or an array reference?
Once you are done check out the other resources you can find on this site and consider supporting me via Patreon .Given an array listing rulers in the Kingdom of Jerusalem like this one: @kings = ('Baldwin', 'Melisende', 'Fulk', 'Amalric', 'Guy', 'Conrad') . How can we create one that is built from the 2nd, the 4th and then the 1st element?
One solution is:
@names = ($kings[2], $kings[4], $kings[1])
The other, the simpler solution is to use array slices:
@names = @kings[2,4,1]
In this case we use the @ prefix of the array and provide several indexes. If you are familiar with arrays in Perl , you surely remember that when we talk about the whole array we put @ in front of the name, but when we talk about a single element of an array we replace the @ sigil by the $ sigil and put square brackets at the end.
When we want create a list of one or more of the elements of the array we use the @ sigil again, as it represents "plural" and then we put one or more indexes in the square brackets after the name of the array.
See the full example here:
examples/array_slice.pl
Scalar value @kings[2] better written as $kings[2]
- use strict ;
- use warnings ;
- use 5.010 ;
- my @kings = ( 'Baldwin' , 'Melisende' , 'Fulk' , 'Amalric' , 'Guy' , 'Conrad' );
- my @names = ( $kings [ 2 ], $kings [ 4 ], $kings [ 1 ]);
- say join ', ' , @names ; # Fulk, Guy, Melisende
- my @slice = @kings [ 2 , 4 , 1 ];
- say join ', ' , @slice ; # Fulk, Guy, Melisende
This warning will appear if you try to use an array slice with a single index as in this example:
my @s = @kings[2];
This is how splain explains the warning:
Scalar value @kings[2] better written as $kings[2] at array_slice.pl line 14 (#1) (W syntax) You've used an array slice (indicated by @) to select a single element of an array. Generally it's better to ask for a scalar value (indicated by $). The difference is that $foo[&bar] always behaves like a scalar, both when assigning to it and when evaluating its argument, while @foo[&bar] behaves like a list when you assign to it, and provides a list context to its subscript, which can do weird things if you're expecting only one subscript.On the other hand, if you were actually hoping to treat the array element as a list, you need to look into how references work, because Perl will not magically convert between scalars and lists for you. See perlref.
If you would like to create a new array using a single element of another array then you should probably write:
my @s = $kings[2];
or if you want to make sure readers of your code won't be surprised by the assignment of a scalar to an array, then you can even put parentheses around the value.
my @s = ($kings[2]);
Slice of an array referenceIf we have out data in an ARRAY reference and not in an array, the code will be a bit more complex:
In this case we have a variable called $kings which is a reference to an array.
In the plain version, when we use individual elements we just need to dereference the ARRAY reference for each individual element.
my @names = ($kings->[2], $kings->[4], $kings->[1]);
If we would like to use the array slice syntax then first we need to dereference the whole array putting the @ sigil in-front of the reference: @$kings , but then we can simply put the square brackets behind that construct: my @slice = @$kings[2,4,1]; though I think I prefer the version when we put curly braces around the reference, thereby making it clear that it is a single unit of expression:
my @slice = @{$kings}[2,4,1];
The full example can be seen here:
examples/array_ref_slice.pl
- use strict ;
- use warnings ;
- use 5.010 ;
- my $kings = [ 'Baldwin' , 'Melisende' , 'Fulk' , 'Amalric' , 'Guy' , 'Conrad' ];
- my @names = ( $kings ->[ 2 ], $kings ->[ 4 ], $kings ->[ 1 ]);
- say join ', ' , @names ; # Fulk, Guy, Melisende
- my @slice = @{ $kings }[ 2 , 4 , 1 ];
- say join ', ' , @slice ; # Fulk, Guy, Melisende
Aug 26, 2020 | stackoverflow.com
never_had_a_name ,
How are non-capturing groups, i.e.
(?:)
, used in regular expressions and what are they good for?aliteralmind ,
This question has been added to the Stack Overflow Regular Expression FAQ , under "Groups". – aliteralmind Apr 10 '14 at 0:25Ricardo Nolde ,
Let me try to explain this with an example.
Consider the following text:
http://stackoverflow.com/ https://stackoverflow.com/questions/tagged/regexNow, if I apply the regex below over it...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?... I would get the following result:
Match "http://stackoverflow.com/" Group 1: "http" Group 2: "stackoverflow.com" Group 3: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "https" Group 2: "stackoverflow.com" Group 3: "/questions/tagged/regex"But I don't care about the protocol -- I just want the host and path of the URL. So, I change the regex to include the non-capturing group
(?:)
.(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?Now, my result looks like this:
Match "http://stackoverflow.com/" Group 1: "stackoverflow.com" Group 2: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "stackoverflow.com" Group 2: "/questions/tagged/regex"See? The first group has not been captured. The parser uses it to match the text, but ignores it later, in the final result.
EDIT:As requested, let me try to explain groups too.
Well, groups serve many purposes. They can help you to extract exact information from a bigger match (which can also be named), they let you rematch a previous matched group, and can be used for substitutions. Let's try some examples, shall we?
Imagine you have some kind of XML or HTML (be aware that regex may not be the best tool for the job , but it is nice as an example). You want to parse the tags, so you could do something like this (I have added spaces to make it easier to understand):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\> or \<(.+?)\> [^<]*? \</\1\>The first regex has a named group (TAG), while the second one uses a common group. Both regexes do the same thing: they use the value from the first group (the name of the tag) to match the closing tag. The difference is that the first one uses the name to match the value, and the second one uses the group index (which starts at 1).
Let's try some substitutions now. Consider the following text:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.Now, let's use this dumb regex over it:
\b(\S)(\S)(\S)(\S*)\bThis regex matches words with at least 3 characters, and uses groups to separate the first three letters. The result is this:
Match "Lorem" Group 1: "L" Group 2: "o" Group 3: "r" Group 4: "em" Match "ipsum" Group 1: "i" Group 2: "p" Group 3: "s" Group 4: "um" ... Match "consectetuer" Group 1: "c" Group 2: "o" Group 3: "n" Group 4: "sectetuer" ...So, if we apply the substitution string:
$1_$3$2_$4... over it, we are trying to use the first group, add an underscore, use the third group, then the second group, add another underscore, and then the fourth group. The resulting string would be like the one below.
L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.You can use named groups for substitutions too, using
${name}
.To play around with regexes, I recommend http://regex101.com/ , which offers a good amount of details on how the regex works; it also offers a few regex engines to choose from.
Ricardo Nolde ,
@ajsie: Traditional (capturing) groups are most useful if you're performing a replacement operation on the results. Here's an example where I'm grabbing comma-separated last & first names and then reversing their order (thanks to named groups)... regexhero.net/tester/?id=16892996-64d4-4f10-860a-24f28dad7e30 – Steve Wortham Aug 19 '10 at 15:43You can use capturing groups to organize and parse an expression. A non-capturing group has the first benefit, but doesn't have the overhead of the second. You can still say a non-capturing group is optional, for example.
Say you want to match numeric text, but some numbers could be written as 1st, 2nd, 3rd, 4th,... If you want to capture the numeric part, but not the (optional) suffix you can use a non-capturing group.
([0-9]+)(?:st|nd|rd|th)?That will match numbers in the form 1, 2, 3... or in the form 1st, 2nd, 3rd,... but it will only capture the numeric part.
Jan 01, 2011 | stackoverflow.com
Ask Question Asked 9 years, 2 months ago Active 6 years, 9 months ago Viewed 995 times Bright futures begin at Lutron View all 4 job openings!
bitbucket , 2011-06-21 23:35:26
I work quit a bit with lib ReadLine and the lib Perl Readline.
Yet, the Perl debugger refuses to save the session command line history.
Thus, each time I invoke the debugger I lose all of my previous history.
Does anyone know how to have the Perl debugger save, and hopefully, append session history similar to the bash
HISTORYFILE
?eli ,
just for anyone else looking for that: for readline to work in perl (ctrl-p / ctrl-n / ...) one has toapt-get install libterm-readline-gnu-perl
(at least in debian) – eli Jun 7 '18 at 14:13ysth ,
The way I do this is by having the following line in my
~/.perldb
file:
&parse_options("HistFile=$ENV{HOME}/.perldb.hist");
Debugger commands are then stored in
~/.perldb.hist
and accessible across sessions.ysth ,
@bitbucket: I've had enough problems in the past getting the built-in readline support working that I don't even bother anymore :) – ysth Jun 22 '11 at 16:59
Aug 19, 2020 | perldoc.perl.org
Perl functions A-Z | Perl functions by category | The 'perlfunc' manpage
- splice ARRAY,OFFSET,LENGTH,LIST
- splice ARRAY,OFFSET,LENGTH
- splice ARRAY,OFFSET
- splice ARRAY
Removes the elements designated by OFFSET and LENGTH from an array, and replaces them with the elements of LIST, if any. In list context, returns the elements removed from the array. In scalar context, returns the last element removed, or undef if no elements are removed. The array grows or shrinks as necessary. If OFFSET is negative then it starts that far from the end of the array. If LENGTH is omitted, removes everything from OFFSET onward. If LENGTH is negative, removes the elements from OFFSET onward except for -LENGTH elements at the end of the array. If both OFFSET and LENGTH are omitted, removes everything. If OFFSET is past the end of the array and a LENGTH was provided, Perl issues a warning, and splices at the end of the array.
The following equivalences hold (assuming
$#a >= $i
)
- push ( @a , $x , $y ) splice ( @a , @a , 0 , $x , $y )
- pop ( @a ) splice ( @a , -1 )
- shift ( @a ) splice ( @a , 0 , 1 )
- unshift ( @a , $x , $y ) splice ( @a , 0 , 0 , $x , $y )
- $a [ $i ] = $y splice ( @a , $i , 1 , $y )
splice can be used, for example, to implement n-ary queue processing:
- sub nary_print {
- my $n = shift ;
- while ( my @next_n = splice @_ , 0 , $n ) {
- say join q{ -- } , @next_n ;
- }
- }
- nary_print ( 3 , qw(a b c d e f g h) ) ;
- # prints:
- # a -- b -- c
- # d -- e -- f
- # g -- h
Starting with Perl 5.14, an experimental feature allowed splice to take a scalar expression. This experiment has been deemed unsuccessful, and was removed as of Perl 5.24.
Jan 01, 2009 | stackoverflow.com
How do I add an array ref to the middle of an existing array in Perl? Ask Question Asked 11 years, 2 months ago Active 6 years, 7 months ago Viewed 6k times
https://tpc.googlesyndication.com/safeframe/1-0-37/html/container.html Report this ad
, 2009-06-22 03:09:37
I want to be able to place an array into an array. For example, I may have an array like this:
my @array1 = ("element 1","element 2","element 3");Then I have another array
my $array_ref = ["this will", "go between", "element 1 and 2"];I want to place
$array_ref
into the first so that the first array looks like this:("element 1",["this will", "go between", "element 1 and 2"],"element 2","element 3")I can't seem to do this. I looked all over Google and found nothing.
Telemachus ,
The second one is not an array. It is an array reference. – Alan Haggai Alavi Jun 22 '09 at 4:26ysth , 2009-06-22 03:28:29
So you use splice to replace 0 elements beginning with element 1 (the second element, the first is element 0) with your desired elements:
splice( @array, 1, 0, ["this will", "go between", "element 1 and 2"] );Or possibly you mean:
splice( @array, 1, 0, "this will", "go between", "element 1 and 2" );if you don't want nested arrays.
Nic Gibson ,
I think he meant insert into an existing array too. Not totally clear though. – Nic Gibson Jun 22 '09 at 8:47aks ,
The important point to remember is the distinction between () and []. '()' gives you a list of elements, for eg. (1, 2, 3) which you could then assign to an array variable as so -
my @listOfElem = (1, 2, 3);'[]' is an array reference and returns a scalar value which you could incorporate into your list.
my $refToElem = ['a', 'b', 'c'];In your case, if you are initializing the first array then you could simply insert the second array elements like so,
my @listOfElem = (1, 2, ['a', 'b', 'c'], 3); #This gives you a list of "4" elements with the third #one being an array reference my @listOfElem = (1, 2, $refToELem, 3); #Same as above, here we insert a reference scalar variable my @secondListOfElem = ('a', 'b', 'c'); my @listOfElem = (1, 2, \@secondListOfElem, 3); #Same as above, instead of using a scalar, we insert a reference #to an existing array which, presumably, is what you want to do. #To access the array within the array you would write - $listOfElem[2]->[0] #Returns 'a' @{listOfElem[2]}[0] #Same as above.If you have to add the array elements on the fly in the middle of the array then just use 'splice' as detailed in the other posts.
> ,
add a commentbrian d foy , 2009-06-22 13:36:27
This is the sort of thing you'll understand after going through the first part of Intermediate Perl , which covers references and data structures. You can also look in the Perl data structures cookbook .
In short, you store an array in another array by using a reference (which is just a scalar):
my @big_array = ( $foo, $bar, \@other_array, $baz );In your case, you used the anonymous array constructor and just want to splice it into an existing array. There's nothing special about it being an array reference:
splice @big_array, $offset, $length, @new_items;In your case, you wanted to start at element 1, remove 0 items, and add your reference:
splice @big_array, 1, 0, $array_ref;> ,
add a commentanonymous coward , 2009-06-22 03:18:52
Try having a temporary array, like this:
@temp_arr = ("this will", "go between", "element 1 and 3"); @my_arr = ("element 1", \@temp_arr, "element 3");You can use the sub-elements like this:
print $my_arr[1]->[0]; # prints 'this will'Refer to the subarray like this:
print @$my_arr[1]; # Right! Prints 'this willgo betweenelement 1 and 2' # Don't do this: print $my_arr[1]; # Wrong! Prints something like: 'ARRAY(0xDEADBEEF)'Ape-inago ,
I agree, use references. – Ape-inago Jun 22 '09 at 3:20Alan Haggai Alavi , 2009-06-22 04:35:10
What you have is an array and an array reference.
#!/usr/bin/perl use strict; use warnings; my @array = ("element 1","element 2","element 3"); my $arrayref = ["this will", "go between", "element 1 and 2"]; splice( @array, 1, 0, $arrayref ); # Grow the array with the list (which is $arrayref) for ( my $i = 0; $i <= $#array; $i++ ) { print "\@array[$i] = $array[$i]\n"; }> ,
add a comment> ,
Use splice .
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @array1 = ("element 1", "element 2", "element 3"); my $array_ref = ["this will", "go between", "element 1 and 2"]; splice(@array1, 1, 0, $array_ref); print Dumper \@array1;This will print the following:
$VAR1 = [ 'element 1', [ 'this will', 'go between', 'element 1 and 2' ], 'element 2', 'element 3' ];
Aug 17, 2020 | perlmonks.org
on Aug 14, 2020 at 02:21 UTC ( # 11120703 = perlquestion : print w/replies , xml ) Need Help?? likbez has asked for the wisdom of the Perl Monks concerning the following question: Reputation: 5
It looks like Perl split function treats single quotes literal semantically inconsistently with other constructs
But not always :-). For example
($line)=split(' ',$line,1)is treated consistently (in AWK way). This is the only way I know to avoid using regex for a very common task of trimming the leading blanks.In general, split function should behave differently if the first argument is string and not a regex. But right now single quoted literal is treated as regular expression. For example:
$line="head xxx tail"; say split('x+',$line);will printhead tailAm I missing something? BTW this would be similar to Python distinguishing between split and re.split but in a more elegant, Perlish way. And a big help for sysadmins.
jwkrahn on Aug 14, 2020 at 03:33 UTC
Re: Why split function treats single quotes literals as regex, instead of a special case?The single space character is a special case for split, anything else is treated as a regular expression, be it a string, function call, etc.
Regular expressions are also treated a bit differently than regular expressions in qr//, m// and s///.
AnomalousMonk on Aug 14, 2020 at 04:38 UTC
Re^2: Why split function treats single quotes literals as regex, instead of a special case?
by AnomalousMonk on Aug 14, 2020 at 04:38 UTCThe single space character is a special case for split ...I.e., per split :As another special case, split emulates the default behavior of the command line tool awk when the PATTERN is either omitted or a string composed of a single space character (such as ' ' or "\x20" , but not e.g. / / ). In this case, any leading whitespace in EXPR is removed before splitting occurs, and the PATTERN is instead treated as if it were /\s+/ ; in particular, this means that any contiguous whitespace (not just a single space character) is used as a separator.You also write:Regular expressions are also treated a bit differently than regular expressions in qr//, m// and s///.I don't understand this statement. Can you elaborate? Give a man a fish : <%-{-{-{-<jwkrahn on Aug 14, 2020 at 09:16 UTC
Re^3: Why split function treats single quotes literals as regex, instead of a special case?
by jwkrahn on Aug 14, 2020 at 09:16 UTCThe regular expression // works differently in split then elsewhere:
$ perl -le' my $x = "1234 abcd 5678"; print $& if $x =~ /[a-z]+/; print $& if $x =~ //; print map qq[ "$_"], split /[a-z]+/, $x; print map qq[ "$_"], split //, $x; ' abcd abcd "1234 " " 5678" "1" "2" "3" "4" " " "a" "b" "c" "d" " " "5" "6" "7" "8" [download]Also, the line anchors /^/ and /$/ don't require the /m option to match lines in a string.
AnomalousMonk on Aug 14, 2020 at 18:17 UTC
Re^4: Why split function treats single quotes literals as regex, instead of a special case?
by AnomalousMonk on Aug 14, 2020 at 18:17 UTCjcb on Aug 14, 2020 at 23:07 UTC
Re^4: Why split function treats single quotes literals as regex, instead of a special case?
by jcb on Aug 14, 2020 at 23:07 UTCAnonymous Monk on Aug 14, 2020 at 10:02 UTC
Re: Why split function treats single quotes literals as regex, instead of a special case?perldoc -f split
perlfan on Aug 14, 2020 at 16:51 UTC
Re: Why split function treats single quotes literals as regex, instead of a special case?> Am I missing something?
Yes, this is Perl not Python.
> Why?
I can assert that conextually, splitting on all characters for split //, $string is a lot more meaningful than splitting on nothing and returning just the original $string . The big surprise actually happens for users (like me) who don't realize the first parameter of split is a regular expression. But that surprise quickly turns into joy .
> In general, split function should behave differently if the first argument is string and not a regex.
Should ? That's pretty presumptuous. You'll notice that Perl has FAR few built in functions (particularly string functions) than PHP, JavaScript, or Python. This is because they've all been generalized away into regular expressions. You must also understand that the primary design philosphy is more related to spoken linquistics than written code. The implication here is that humans are lazy and don't want to learn more words than they need to communicate - not true of all humans, of course. But true enough for 99% of them. This is also reflected in the Huffmanization of most Perl syntax. This refers to Huffman compression, which necessarily compresses more frequently used things (characters, words, etc) into the symbols of the smallest size. I mean Perl isn't APL, but certainly gets this idea from it.
The balkanization of built-in functions that are truly special cases of a general case is against any philosophical underpinnings that Perl follows. I am not saying it's perfect, but it is highly resistent to becoming a tower of babble. If that's your interest (not accusing you of being malicious), there are more fruitful avenues to attack Perl. Most notably, the areas of object orientation and threading. But you'll have pretty much zero success convincing anyone who has been around Perl for a while that the approach to split is incorrect .
Oh, also a string (as you're calling it) is a regular expression in the purest sense of the term . It's best described as a concatenation of a finite set of symbols in fixed ordering. For some reason a lot of people think this regex magic is only present in patterns that may have no beginning or no end, or neither. In your case it just happens to have both. Doesn't make it any less of a regular expression, though.
you !!! on Aug 14, 2020 at 19:29 UTC
Re^2: Why split function treats single quotes literals as regex, instead of a special case?
by you !!! on Aug 14, 2020 at 19:29 UTC Reputation: 5The balkanization of built-in functions that are truly special cases of a general case is against any philosophical underpinnings that Perl follows. I am not saying it's perfect, but it is highly resistant to becoming a tower of babble. If that's your interest (not accusing you of being malicious), there are more fruitful avenues to attack PerlI respectfully disagree. Perl philosophy states that there should be shortcuts for special cases if they are used often. That's the idea behind suffix conditionals ( return if (index($line,'EOL')>-1) ) and bash-style if statement ( ($debug) && say line; )
You also are missing the idea. My suggestion is that we can enhance the power of Perl by treating single quoted string differently from regex in split. And do this without adding to balkanization.
Balkanization of built-ins is generally what Python got having two different functions. Perl can avoid this providing the same functionality with a single function. That's the idea.
And my point is that this particular change requires minimal work in interpreter as it already treats ' ' in a special way (AWK way).
So this is a suggestion for improving the language, not for balkanization, IMHO. And intuitively it is logical as people understand (and expect) the difference in behavior between single quoted literals and regex in split. So, in a way, the current situation can be viewed as a bug, which became a feature.
perlfan on Aug 15, 2020 at 08:04 UTC
Re^3: Why split function treats single quotes literals as regex, instead of a special case?
by perlfan on Aug 15, 2020 at 08:04 UTC So, in a way, the current situation can be viewed as a bug, which became a feature.To be fair, this is a lot of perl . But I can't rightfully assert that this behavior was unintentional, in fact it appears to be very intentional (e.g., awk emulation).
> You also are missing the idea.
My understanding is that you wish for "strings" (versus "regexes") to invoke the awk behavior of trimming leading white space. Is that right? I'm not here to judge your suggestion, but I can easily think of several reasons why adding another special case to split is not a great idea.
All I can say is you're the same guy who was looking for the trim method in Perl. If that's not a red flag for being okay with balkanization , I don't know what is.
Finally, I must reiterate. A "string" is a regular expression . The single quoted whitespace is most definitely a special exception since it is also a regular expression. You're recommending not only removing one regex from the pool of potential regexes, but an entire class of them available via quoting - i.e., fixed length strings of a fixed ordering. I am not sure how this is really a suggestion of making all quoted things not be regexes, because then how do you decide if it is "regex" or not? (maybe use a regex? xD)
- Comment on Why split function treats single quotes literals as regex, instead of a special case?
- Select or Download Code
- Send private /msg to likbez
Replies are listed 'Best First'.
Aug 16, 2020 | perlmonks.org
on Aug 15, 2020 at 18:21 UTC ( # 11120786 = perlquestion : print w/replies , xml ) Need Help?? likbez has asked for the wisdom of the Perl Monks concerning the following question:
The system function undef can be used on the right side of split function or array assignment to skip values that you do not need. For example:
$current_time='14:30:05' (undef, $min, $sec)=$current_timeIn this role it is similar to /dev/null in Unix.
But if used on the right side this function deletes the variable from the symbol table, For example
$line=undef; say "Does not exists" unless(defined($line));Is this correct understanding?
Aug 16, 2020 | perlmonks.org
on Aug 14, 2020 at 02:24 UTC ( # 11120704 = perlquestion : print w/replies , xml ) Need Help?? likbez has asked for the wisdom of the Perl Monks concerning the following question: Reputation: 4
Is there any way to trim both leading and trailing blanks in a text line (one of the most common operations in text processing; often implemented as trim function which BTW was present in Perl 6) without resorting to regular expressions (which are definitely an overkill for this particular purpose)? This is clearly an important special case.
So far the most common solution is to use something like $line =~ s/^\s+|\s+$//g which clearly is an abuse of regex.
See, for example, https://perlmaven.com/trim
Or install String::Util which is a not a standard module and as such creates difficulties in enterprise env.
hippo on Aug 14, 2020 at 06:46 UTC
Re: How to trim a line from leading and trailing blanks without using regex or non-standard moduleswithout resorting to regular expressions (which are definitely an overkill for this particular purpose)?Sure, just write your own function to do it. Having written that you will then come to the conclusion that regular expressions are definitely not an overkill for this particular purpose.
This is clearly an important special case. ... which clearly is an abuse of regex.You keep using that word. I don't think it means what you think it means.
🦛LanX on Aug 14, 2020 at 03:28 UTC
Re: How to trim a line from leading and trailing blanks without using regex or non-standard modules> which clearly is an abuse of regex.
Why is it an abuse of regex?
Problem is that \s is a meta character for any white-space not only blank " " , but only usable inside regex.°
So if you want the exact same semantic, it'll become far more complicated than this regex.
But better define your own trim() using a regex inside.
Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monasteryyou !!! on Aug 14, 2020 at 19:39 UTC
Re^2: How to trim a line from leading and trailing blanks without using regex or non-standard modules
by you !!! on Aug 14, 2020 at 19:39 UTC Reputation: 6So if you want the exact same semantic, it'll become far more complicated than this regex.I agree. That's a good point. Thank you !
In other words it is not easy to design a good trim function without regex, but it is possible to design one that used regex, but treating the single quoted string as a special case
For example
trim(' ',$line)vstrim(/\s/.$line)BTW this is impossible in Python which implements regex via library, unless you add a new lexical type to the Language (regex string instead of raw string that is used).LanX on Aug 15, 2020 at 01:04 UTC
Re^3: How to trim a line from leading and trailing blanks without using regex or non-standard modules
by LanX on Aug 15, 2020 at 01:04 UTC > trim(/\s/.$line)I doubt this is valid syntax.
you probably mean
trim( qr/\s/, $line)
see Re^3: How to trim a line from leading and trailing blanks without using regex or non-standard modules for a slightly better implementation
> this is impossible in Python
passing regex inside a string is fine in Perl, why not in Python?
Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monasterykcott on Aug 14, 2020 at 09:35 UTC
Re: How to trim a line from leading and trailing blanks without using regex or non-standard modulesG'day likbez ,
I will usually reach for one of Perl's string handling functions (e.g. index , rindex , substr , and so on) in preference to a regex when that is appropriate; however, in this case, I would say that the regex makes for much cleaner code.
You could implement a trim() function using the guts of this code (which uses neither a regex nor any modules, standard or otherwise):
$ perl -E ' my @x = (" a b c ", "d e f ", " g h i", "j k l", " ", ""); say "*** Initial strings ***"; say "|$_|" for @x; for my $i (0 .. $#x) { my $str = $x[$i]; while (0 == index $str, " ") { $str = substr $str, 1; } my $str_end = length($str) - 1; while ($str_end == rindex $str, " ") { $str = substr $str, 0, $str_end; --$str_end; } $x[$i] = $str; } say "*** Final strings ***"; say "|$_|" for @x; ' *** Initial strings *** | a b c | |d e f | | g h i| |j k l| | | || *** Final strings *** |a b c| |d e f| |g h i| |j k l| || || [download]If your question was genuinely serious, please Benchmark a trim() function using something like I've provided against another trim() function using a regex. You could obviously do the same for ltrim() and rtrim() functions.
[As others have either asked or alluded to, please explain phrases such as "definitely an overkill", "important special case" and "abuse of regex". Unfortunately, use of such language makes your post come across as some sort of trollish rant -- I'm not saying that was your intent, just how it presents itself.]
-- KenLanX on Aug 14, 2020 at 11:22 UTC
Re^2: How to trim a line from leading and trailing blanks without using regex or non-standard modules
by LanX on Aug 14, 2020 at 11:22 UTCI suppose your solution works only for blank " " and not for other whitespace characters like "\n"
So it's not exactly the same like with \s °
DB<11> $a="x \n \n \n " DB<12> $a =~ s/\s+$// DB<13> x $a 0 'x' DB<14> [download]The OP should be clearer about the semantics he wants.
Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monasterysee also Re: How to trim a line from leading and trailing blanks without using regex or non-standard modules
kcott on Aug 15, 2020 at 11:02 UTC
Re^3: How to trim a line from leading and trailing blanks without using regex or non-standard modules
by kcott on Aug 15, 2020 at 11:02 UTCG'day Rolf ,
That's a valid point. My main intent with that code was really to show the complexity of the solution when a regex or module were not used. Anyway, adding a little more complexity, you can trim whatever blanks you want:
$ perl -E ' my @blanks = (" ", "\n", "\r", "\t"); my @x = ( " a b c ", "d e f \r ", " \t g h i", "j k l", " ", "\n", "\n\nXYZ\n\n", "" ); say "*** Initial strings ***"; say "|$_|" for @x; for my $i (0 .. $#x) { my $str = $x[$i]; while (grep { 0 == index $str, $_ } @blanks) { $str = substr $str, 1; } my $str_end = length($str) - 1; while (grep { $str_end == rindex $str, $_ } @blanks) { $str = substr $str, 0, $str_end; --$str_end; } $x[$i] = $str; } say "*** Final strings ***"; say "|$_|" for @x; ' *** Initial strings *** | a b c | | e f | g h i| |j k l| | | | | | XYZ | || *** Final strings *** |a b c| |d e f| |g h i| |j k l| || || |XYZ| || [download]You're quite correct about "The OP should be clearer ..." . The word 'blank' is often used to mean various things: a single space, multiple consecutive spaces, a whitepace character, multiple consecutive whitepace characters, and I have also seen it used to refer to a zero-length string. Similarly, the word 'space' can mean a single space, any gap between visible characters, and so on. So, as with many posts, we're left with guessing the most likely meaning from the context.
My belief, that a regex is a better option, strengthens as the complexity of the non-regex and non-module code increases. :-)
-- Kenjwkrahn on Aug 14, 2020 at 03:58 UTC
Re: How to trim a line from leading and trailing blanks without using regex or non-standard modules(IMHO) the most common solution is:
s/^\s+//, s/\s+$// for $line; [download]Marshall on Aug 14, 2020 at 04:33 UTC
Re^2: How to trim a line from leading and trailing blanks without using regex or non-standard modules
by Marshall on Aug 14, 2020 at 04:33 UTC
s/^\s+|\s+$//g has been benchmarked. And I now think this is faster and "better" than 2 statements. There is one post at Re^3: script optmization that shows some benchmarks.This is certainly not an "abuse" of regex. This is what regex is is for! The Perl regex engine continually becomes better and usually faster between releases.
perlfan on Aug 14, 2020 at 12:23 UTC
Re: How to trim a line from leading and trailing blanks without using regex or non-standard modules> $line =~ s/^\s+|\s+$//g which clearly is an abuse of regex.
Why do you say that?
> trim function which BTW was present in Perl 6
You say this like it's a good thing. I bet there is also one in PHP.
karlgoethebier on Aug 14, 2020 at 12:34 UTC
Re^2: How to trim a line from leading and trailing blanks without using regex or non-standard modules"The Crux of the Biscuit is the Apostrophe"
by karlgoethebier on Aug 14, 2020 at 12:34 UTCperl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});' Help
LanX on Aug 14, 2020 at 14:43 UTC
Re^3: How to trim a line from leading and trailing blanks without using regex or non-standard modules
by LanX on Aug 14, 2020 at 14:43 UTC DB<33> sub trim { $_[1] //= qr/\s/; $_[0] =~ s/^[$_[1]]+|[$_[1]]+$// + g } DB<34> $a = $b = " \n . aaa . \n " DB<35> trim $a DB<36> trim $b, " " DB<37> x $a,$b 0 '. aaa .' 1 ' . aaa . ' DB<38> [download] Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery
- Comment on How to trim a line from leading and trailing blanks without using regex or non-standard modules
- Select or Download Code
- Send private /msg to likbez
Replies are listed 'Best First'.
Aug 13, 2020 | www.perlmonks.org
by zapdos
on Aug 11, 2020 at 02:09 UTC ( # 11120582 = perlquestion : print w/replies , xml ) Need Help?? zapdos has asked for the wisdom of the Perl Monks concerning the following question:
- log likbez out
- likbez
- The Monastery Gates
- Seekers of Perl Wisdom
- Meditations
- Cool Uses For Perl
- Obfuscation
- Q&A
- Tutorials
- Poetry
- Reviews
- Perl News
- Donate
- Recent Threads
- Newest Nodes
- Super Search
- PerlMonks Discussion
- What's New
$rocks[0] = 'bedrock'; $rocks[1] = 'slate'; $rocks[2]= 'lava'; $rocks[3] = 'crushed rock'; $rocks[99] = 'schist'; $#rocks = 2; # forget all rocks after 'lava' $#rocks = 99; # add 97 undef elements (the forgotten rocks are gone forever)So I'm following the book Learning Perl, there's this code with comments in it: If I do print $rocks[$#rocks]; it prints nothing. Why? When I comment out $#rocks = 99; it prints 'lava' and when I comment out $#rocks = 2; it prints 'schist'.But when I maintain the two it prints nothing as I already said.
And what the comments "add 97 undef elements (the forgotten rocks are gone forever)" and "forget all rocks after 'lava'" mean?
Jan 01, 2011 | stackoverflow.com
Ask Question Asked 9 years, 7 months ago Active 2 years, 11 months ago Viewed 129k times
> ,
Is there a built-in function to trim leading and trailing whitespace such thattrim(" hello world ") eq "hello world"
?Landon Kuhn , 2011-01-04 20:10:52
edited Jan 4 '11 at 20:20 asked Jan 4 '11 at 20:10 Landon Kuhn 58.5k 41 41 gold badges 98 98 silver badges 128 128 bronze badgesdaxim ,
FYI: string equality in Perl is tested by the operatoreq
. – A. Rex Jan 4 '11 at 20:16> ,
Here's one approach using a regular expression:$string =~ s/^\s+|\s+$//g ; # remove both leading and trailing whitespacePerl 6 will include a trim function:
$string .= trim;Source: Wikipedia
Mark Byers , 2011-01-04 20:13:55
edited Oct 28 '12 at 15:23 answered Jan 4 '11 at 20:13 Mark Byers 676k 155 155 gold badges 1464 1464 silver badges 1383 1383 bronze badgeskyle ,
I look this up about once a month. Too bad I can't upvote it each time. – kyle Oct 29 '14 at 19:31Ether , 2011-01-04 20:33:47
This is available in String::Util with thetrim
method:Editor's note:
String::Util
is not a core module, but you can install it from CPAN with[sudo] cpan String::Util
.use String::Util 'trim'; my $str = " hello "; $str = trim($str); print "string is now: '$str'\n";prints:
string is now 'hello'
However it is easy enough to do yourself:
$str =~ s/^\s+//; $str =~ s/\s+$//;Marki555 ,
@mklement0 nor will it ever be. But this is not relevant, since everyone should be using modules from the CPAN. – Ether Jun 9 '15 at 21:12> ,
UncleCarl ,
@Ether With all due respect, I really appreciate knowing that this is a non-core module. This post is talking about using a module in lieu of a fairly simple regex one-liner. If the module is core, I would be much more open to it. It is relevant in this case. – UncleCarl Mar 1 '18 at 16:57> ,
There's no built-intrim
function, but you can easily implement your own using a simple substitution:sub trim { (my $s = $_[0]) =~ s/^\s+|\s+$//g; return $s; }or using non-destructive substitution in Perl 5.14 and later:
sub trim { return $_[0] =~ s/^\s+|\s+$//rg; }Eugene Yarmash ,
edited Aug 18 '17 at 13:50 Flow 21.4k 13 13 gold badges 89 89 silver badges 142 142 bronze badges answered Jan 4 '11 at 20:14 Eugene Yarmash 110k 29 29 gold badges 248 248 silver badges 313 313 bronze badges> ,
add a comment> ,
According to this perlmonk's thread :$string =~ s/^\s+|\s+$//g;brettkelly , 2011-01-04 20:13:55
answered Jan 4 '11 at 20:13 brettkelly 24.3k 8 8 gold badges 49 49 silver badges 66 66 bronze badges> ,
add a comment> ,
Complete howto in the perfaq here: http://learn.perl.org/faq/perlfaq4.html#How-do-I-strip-blank-space-from-the-beginning-end-of-a-string-Nanne , 2011-01-04 20:15:16
edited Jan 6 '12 at 15:51 Michael Kristofik 30.2k 15 15 gold badges 69 69 silver badges 118 118 bronze badges answered Jan 4 '11 at 20:15 Nanne 60.5k 16 16 gold badges 106 106 silver badges 152 152 bronze badges> ,
add a comment> ,
For those that are using Text::CSV I found this thread and then noticed within the CSV module that you could strip it out via switch:$csv = Text::CSV->new({allow_whitespace => 1});The logic is backwards in that if you want to strip then you set to 1. Go figure. Hope this helps anyone.
Douglas ,
answered Dec 3 '14 at 16:44 Douglas 259 2 2 silver badges 15 15 bronze badges> ,
add a comment> ,
One option is Text::Trim :use Text::Trim; print trim(" example ");
Feb 27, 2020 | alvinalexander.com
By Alvin Alexander. Last updated: November 21 2019 Table of Contents
- printf formatting with Perl and Java
- A summary of printf format specifiers
- Controlling integer width with printf
- Left-justifying printf integer output
- The printf integer zero-fill option
- printf integer formatting
- formatting floating point numbers with printf
- printf string formatting
- printf special characters
- Related printf content
Summary: This page is a printf formatting cheat sheet. I originally created this cheat sheet for my own purposes, and then thought I would share it here.
A great thing about the
Back to top printf formatting with Perl and Javaprintf
formatting syntax is that the format specifiers you can use are very similar -- if not identical -- between different languages, including C, C++, Java, Perl, PHP, Ruby, Scala, and others. This means that yourprintf
knowledge is reusable, which is a good thing.In this cheat sheet I'll show all the examples using Perl, but at first it might help to see one example using both Perl and Java. Therefore, here's a simple Perl
printf
example to get things started:printf("the %s jumped over the %s, %d times", "cow", "moon", 2);And here are three different Java
printf
examples, using different string formatting methods that are available to you in the Java programming language:System.out.format("the %s jumped over the %s, %d times", "cow", "moon", 2); System.err.format("the %s jumped over the %s, %d times", "cow", "moon", 2); String result = String.format("the %s jumped over the %s, %d times", "cow", "moon", 2);As you can see in that last
String.format
example, that line of code doesn't print any output, while the first line prints to standard output, and the second line prints to standard error.In the remainder of this document I'll use Perl examples, but again, the actual format specifier strings can be used in many different languages.
Back to top A summary of printf format specifiersHere's a quick summary of the available
printf
format specifiers:Back to top Controlling integer width with printf
%c character %d decimal (integer) number (base 10) %e exponential floating-point number %f floating-point number %i integer (base 10) %o octal number (base 8) %s a string of characters %u unsigned decimal (integer) number %x number in hexadecimal (base 16) %% print a percent sign \% print a percent sign The
%3d
specifier is used with integers, and means a minimum width of three spaces, which, by default, will be right-justified:Back to top Left-justifying printf integer output
printf("%3d", 0); 0 printf("%3d", 123456789); 123456789 printf("%3d", -10); -10 printf("%3d", -123456789); -123456789 To left-justify integer output with
printf
, just add a minus sign (-
) after the%
symbol, like this:Back to top The printf integer zero-fill option
printf("%-3d", 0); 0 printf("%-3d", 123456789); 123456789 printf("%-3d", -10); -10 printf("%-3d", -123456789); -123456789 To zero-fill your
printf
integer output, just add a zero (0
) after the%
symbol, like this:Back to top printf integer formatting
printf("%03d", 0); 000 printf("%03d", 1); 001 printf("%03d", 123456789); 123456789 printf("%03d", -10); -10 printf("%03d", -123456789); -123456789 As a summary of
printf
integer formatting, here's a little collection of integer formatting examples. Several different options are shown, including a minimum width specification, left-justified, zero-filled, and also a plus sign for positive numbers.Back to top formatting floating point numbers with printf
Description Code Result At least five wide printf("'%5d'", 10); ' 10' At least five-wide, left-justified printf("'%-5d'", 10); '10 ' At least five-wide, zero-filled printf("'%05d'", 10); '00010' At least five-wide, with a plus sign printf("'%+5d'", 10); ' +10' Five-wide, plus sign, left-justified printf("'%-+5d'", 10); '+10 ' Here are several examples showing how to format floating-point numbers with
printf
:Back to top printf string formatting
Description Code Result Print one position after the decimal printf("'%.1f'", 10.3456); '10.3' Two positions after the decimal printf("'%.2f'", 10.3456); '10.35' Eight-wide, two positions after the decimal printf("'%8.2f'", 10.3456); ' 10.35' Eight-wide, four positions after the decimal printf("'%8.4f'", 10.3456); ' 10.3456' Eight-wide, two positions after the decimal, zero-filled printf("'%08.2f'", 10.3456); '00010.35' Eight-wide, two positions after the decimal, left-justified printf("'%-8.2f'", 10.3456); '10.35 ' Printing a much larger number with that same format printf("'%-8.2f'", 101234567.3456); '101234567.35' Here are several examples that show how to format string output with
printf
:Back to top printf special characters
Description Code Result A simple string printf("'%s'", "Hello"); 'Hello' A string with a minimum length printf("'%10s'", "Hello"); ' Hello' Minimum length, left-justified printf("'%-10s'", "Hello"); 'Hello ' The following character sequences have a special meaning when used as
printf
format specifiers:
\a audible alert \b backspace \f form feed \n newline, or linefeed \r carriage return \t tab \v vertical tab \\ backslash As you can see from that last example, because the backslash character itself is treated specially, you have to print two backslash characters in a row to get one backslash character to appear in your output.
Here are a few examples of how to use these special characters:
Back to top Related printf content
Description Code Result Insert a tab character in a string printf("Hello\tworld"); Hello world Insert a newline character in a string printf("Hello\nworld"); Hello
worldTypical use of the newline character printf("Hello world\n"); Hello world A DOS/Windows path with backslash characters printf("C:\\Windows\\System32\\"); C:\Windows\System32\ Here are a few links to other "printf" tutorials on my website:
And here's a link to the Java formatter javadoc .
Back to top java string source ruby reference printf perl java format cheatsheet c++ c scala sprintfbooks i've written
- Java String formatting with the String.format method (like 'sprintf')
- Java 'printf' - formatting output with System.out.format
- Does Scala have a String variable substitution syntax like Ruby?
- How to use multiple regex patterns with replaceAll (Java String class)
- How to generate Java FreeMarker output as a String
- Scala String.format error: overloaded method value format with alternatives
Comments
- Sanctify Yourself
- The solitude of hiking in Alaska (Seward)
- The Girl Who Loved to Dance
- A garbage dumpster in Seward, Alaska
- Tour boat, Resurrection Bay, Seward, Alaska
- Killer whales in Alaska
Submitted by Anonymoose (not verified) on November 5, 2009 - 10:36am
Permalink I have to commend you, you've I have to commend you, you've created a very easy to read manual on the basics of the printf function. That's a feat in and of itself. Bookmarked!
- Log in to post comments
Submitted by Anonymous (not verified) on March 24, 2010 - 9:57pm
Permalink Cool Thanks this really helped ;)
- Log in to post comments
Submitted by Anonymous (not verified) on June 11, 2010 - 9:10pm
Permalink Great job ! Thanks ! ^^
- Log in to post comments
Submitted by alvin on October 9, 2010 - 6:15pm
Permalink printf formatting problems fixed Sorry for the long delay, but hopefully I've finally fixed the formatting problems with this article. If you see any errors please let me know, and I'll try to get them corrected.
- Log in to post comments
Submitted by Anonymous (not verified) on November 7, 2010 - 5:37am
Permalink Neeeeat! :) Really helpful! :)
- Log in to post comments
Submitted by Anonymous (not verified) on October 29, 2018 - 6:33am
Permalink Wonderful! Thank you! This is wonderfully easy to use.Links: front page alvin on twitter search privacy terms & conditions alvinalexander.com
- Log in to post comments
is owned and operated by
Valley Programming, LLCIn regards to links to Amazon.com, As an Amazon Associate
I (Valley Programming, LLC) earn from qualifying purchasesThis website uses cookies: learn more
- java
- java applets
- java faqs
- misc content
- java source code
- test projects
- lejos
- Perl
- perl faqs
- programs
- perl recipes
- perl tutorials
- Unix
- man (help) pages
- unix by example
- tutorials
- source code
warehouse- java examples
- drupal examples
- misc
- privacy policy
- terms & conditions
- subscribe
- unsubscribe
- wincvs tutorial
- function point
analysis (fpa)- fpa tutorial
This website uses cookies: learn more
- Other
- contact me
- rss feed
- my photos
- life in alaska
- how i sold my business
- living in talkeetna, alaska
- my bookmarks
- inspirational quotes
- source code snippets
alvinalexander.com is owned and operated by Valley Programming, LLC
In regards to links to Amazon.com, "As an Amazon Associate
I (Valley Programming) earn from qualifying purchases"
Jan 01, 2009 | stackoverflow.com
Ask Question Asked 10 years, 7 months ago Active 3 years, 5 months ago Viewed 18k times
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Jan 01, 2009 | stackoverflow.com
How can I export all subs in a Perl package? Ask Question Asked 10 years, 7 months ago Active 3 years, 5 months ago Viewed 18k times
Ville M ,
I would like to expose all subs into my namespace without having to list them one at a time:@EXPORT = qw( firstsub secondsub third sub etc );Using fully qualified names would require bunch of change to existing code so I'd rather not do that.
Is there @EXPORT_ALL?
I think documentation says it's a bad idea, but I'd like to do it anyway, or at least know how.
To answer Jon's why: right now for quick refactoring I want to move of bunch of subs into their own package with least hassle and code changes to the existing scripts (where those subs are currenty used and often repeated).
Also, mostly, I was just curious. (since it seemed like that Exporter might as well have that as standard feature, but somewhat surprisingly based on answers so far it doesn't)
brian d foy , 2009-04-08 23:58:35
Don't do any exporting at all, and don't declare a package name in your library. Just load the file withrequire
and everything will be in the current package. Easy peasy.Michael Carman , 2009-04-09 00:15:10
Don't. But if you really want to... write a customimport
that walks the symbol table and export all the named subroutines.# Export all subs in package. Not for use in production code! sub import { no strict 'refs'; my $caller = caller; while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) { next if $name eq 'BEGIN'; # don't export BEGIN blocks next if $name eq 'import'; # don't export this sub next unless *{$symbol}{CODE}; # export subs only my $imported = $caller . '::' . $name; *{ $imported } = \*{ $symbol }; } }Chas. Owens ,
Warning, the code following is as bad an idea as exporting everything:package Expo; use base "Exporter"; seek DATA, 0, 0; #move DATA back to package #read this file looking for sub names our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>; my $sub = sub {}; #make sure anon funcs aren't grabbed sub foo($) { print shift, "\n"; } sub bar ($) { print shift, "\n"; } sub baz{ print shift,"\n"; } sub quux { print shift,"\n"; } 1; __DATA__Here is the some code that uses the module:
#!/usr/bin/perl use strict; use warnings; use Expo; print map { "[$_]\n" } @Expo::EXPORT; foo("foo"); bar("bar"); baz("baz"); quux("quux");And here is its output:
[foo] [bar] [baz] [quux] foo bar baz quuxJon Ericson , 2009-04-08 22:33:36
You can always call subroutines in there fully-specified form:MyModule::firstsub();For modules I write internally, I find this convention works fairly well. It's a bit more typing, but tends to be better documentation.
Take a look at
perldoc perlmod
for more information about what you are trying to accomplish.More generally, you could look at
Exporter
's code and see how it uses glob aliasing. Or you can examine your module's namespace and export each subroutine. (I don't care to search for how to do that at the moment, but Perl makes this fairly easy.) Or you could just stick your subroutines in themain
package:package main; sub firstsub() { ... }(I don't think that's a good idea, but you know better than I do what you are trying to accomplish.)
There's nothing wrong with doing this provided you know what you are doing and aren't just trying to avoid thinking about your interface to the outside world.
ysth , 2009-04-09 01:29:04
Perhaps you would be interested in one of the Export* modules on CPAN that lets you mark subs as exportable simply by adding an attribute to the sub definition? (Don't remember which one it was, though.)echo , 2014-10-11 18:23:01
https://metacpan.org/pod/Exporter::AutoExporter::Auto. this is all you need.
Tero Niemi , 2013-04-02 00:32:25
Although it is not usually wise to dump allsub
s from module into the caller namespace, it is sometimes useful (and more DRY!) to automatically generate@EXPORT_OK
and%EXPORT_TAGS
variables.The easiest method is to extend the Exporter. A simple example is something like this:
package Exporter::AutoOkay; # # Automatically add all subroutines from caller package into the # @EXPORT_OK array. In the package use like Exporter, f.ex.: # # use parent 'Exporter::AutoOkay'; # use warnings; use strict; no strict 'refs'; require Exporter; sub import { my $package = $_[0].'::'; # Get the list of exportable items my @export_ok = (@{$package.'EXPORT_OK'}); # Automatically add all subroutines from package into the list foreach (keys %{$package}) { next unless defined &{$package.$_}; push @export_ok, $_; } # Set variable ready for Exporter @{$package.'EXPORT_OK'} = @export_ok; # Let Exporter do the rest goto &Exporter::import; } 1;Note the use of
goto
that removes us from the caller stack.A more complete example can be found here: http://pastebin.com/Z1QWzcpZ It automatically generates tag groups from subroutine prefixes.
Sérgio , 2013-11-14 21:38:06
case 1Library is :
package mycommon; use strict; use warnings; sub onefunctionthatyoumadeonlibary() { } 1;you can use it, calling common:: :
#!/usr/bin/perl use strict; use warnings; use mycommon; common::onefunctionthatyoumadeonlibary()case 2Library is , yousimple export them :
package mycommon; use strict; use warnings; use base 'Exporter'; our @EXPORT = qw(onefunctionthatyoumadeonlibary); sub onefunctionthatyoumadeonlibary() { } 1;use it in same "namespace":
#!/usr/bin/perl use strict; use warnings; use mycommon qw(onefunctionthatyoumadeonlibary); onefunctionthatyoumadeonlibary()Also we can do a mix of this two cases , we can export more common functions to use it without calling the packages name and other functions that we only call it with package name and that ones don't need to be exported.
> ,
You will have to do some typeglob munging. I describe something similar here:Is there a way to "use" a single file that in turn uses multiple others in Perl?
The import routine there should do exactly what you want -- just don't import any symbols into your own namespace.
Nov 29, 2019 | www.quora.com
Joe Venetos , history, European Union and politics, int'l relations Answered Aug 22 2017 · Author has 485 answers and 325k answer views
Neither.
The USSR as it was was not sustainable, and the writing was all over the wall.
The reason it wasn't sustainable, however, is widely misunderstood.
The Soviet Union could have switched to a market or hybrid economy and still remained a unified state. However, it was made up of 15 very different essentially nation-states from Estonia to Uzbekistan, and separatist movements were tearing the Union apart.
Unlike other multi-national European empires that met their day earlier in the 20th century, such as the British, French, Portuguese, Austro-Hungarian, or Ottoman Empires, the Russian Empi...
(more) LoadingNeither.
The USSR as it was was not sustainable, and the writing was all over the wall.
The reason it wasn't sustainable, however, is widely misunderstood.
The Soviet Union could have switched to a market or hybrid economy and still remained a unified state. However, it was made up of 15 very different essentially nation-states from Estonia to Uzbekistan, and separatist movements were tearing the Union apart.
Unlike other multi-national European empires that met their day earlier in the 20th century, such as the British, French, Portuguese, Austro-Hungarian, or Ottoman Empires, the Russian Empire never had the chance to disband; the can was simply kicked down the road by the Bolshevik revolution and the Soviet era. Restrictions on free speech and press, followed by a gradual economic downturn that began in the 1970s, brewed anti-Union and separatist sentiments among sizeable sections of society. It's important to note, however, that not everyone wanted the disband the USSR, and not everyone in the Russian republic wanted to keep it together (the Central Asian states were the most reluctant to secede). There was, actually, a referendum on whether or not to keep the Union together, and a slight majority voted in favor (something Gorbachev points out to this day), but the vote was also boycotted by quite a few people, especially in the Baltic republics. So, we know that the citizens had mixed feelings and the reasons for the USSR's end were far more complex than just "communism failed".
By the summer of 1991, there was nothing Gorbachev could do. The hardliners saw him as incompetent to save the Union, but too many citizens and military personnel had defected to the politicians of the constituent republics (rather than the Union's leadership), including Russia itself, that were increasingly pursuing their independence since the first multiparty elections across the Union in 1989. By December 1991, Union-level political bodies agreed to disband. So, Gorbachev had no choice but to admit that the USSR no longer existed.
Gorbachev could have ruled with an iron fist, and he could have done so from the 1985 without ever implementing glasnost and perestroika, but that could have been a disaster. We don't really know, actually, but in my opinion, an oligarchy -which is what the USSR was in its later years, not an authoritarian state like it was under Stalin- still needs some level of public consent to continue governing, like China (which is also a diverse society, but far more homogenous than the USSR was). If you have all this economic and separatist malaise brewing, it's not going to work out.
In the long run, Russia is much better off. They now have a state where ethnic Russians make up 80% of the population (a good balance), from what was, I think 50% in the USSR.
While some Russians regret that the USSR ended, others don't care or were ready to call themselves "Russian" rather than "Soviet". It's no different to French public opinion turning against the Algerian war in the 1960s and supporting Algerian independence, or British public opinion starting to support the independence of India yet some people from those countries, may look back fondly. Also, Russia went through a tough economic period in the 1990s, which strengthened Soviet nostalgia, understandably, thinking back to a time when the state guaranteed everyone with housing and a job. While some sentiments still exist today in the Russian Federation that may appear pro-Soviet, it's important to point out that that doesn't necessarily mean these folks would like to recreate the Soviet Union as it was . Many just simply miss the heaftier influence the USSR had, versus what they perceive to be weakness or disrespect for Russia today. The communist party today gets few votes in Russian elections; and many Russians now were not adults prior to 1991, and thus don't quite remember the era too well; many others may be old enough to remember the economic downturn of the 80s, and not the economic good times of the 60s.
One final point, regarding Gorbachev being a "stooge of the West": that gives far too much credit to America under Reagan for taking down the USSR. The "West" had nothing to do with it. In the longer run, as we may be seeing slowly unravel since the Bush Jr administration, America pretty much screwed itself with the massive military spending that started in the 80s and continues upward, with supporting the mujahedeen to lure the USSR into Afghanistan in 1979 (a war that lasted until 1989), with opposing any secular regime in the Middle East friendly to Moscow in the 70s and 80s, and so on we all know how these events started playing out for the US much later, from 9/11 to the current Trump mess.
Jan 01, 2012 | stackoverflow.com
Ask Question Asked 7 years, 5 months ago Active 2 years, 8 months ago Viewed 12k times
Charles , 2012-05-31 20:50:19
I'm looking for advice on Perl best practices. I wrote a script which had a complicated regular expression:my $regex = qr/complicated/; # ... sub foo { # ... if (/$regex/) # ... }where
foo
is a function which is called often, and$regex
is not used outside that function. What is the best way to handle situations like this? I only want it to be interpreted once, since it's long and complicated. But it seems a bit questionable to have it in global scope since it's only used in that sub. Is there a reasonable way to declare it static?A similar issue arises with another possibly-unjustified global. It reads in the current date and time and formats it appropriately. This is also used many times, and again only in one function. But in this case it's even more important that it not be re-initialized, since I want all instances of the date-time to be the same from a given invocation of the script, even if the minutes roll over during execution.
At the moment I have something like
my ($regex, $DT); sub driver { $regex = qr/complicated/; $DT = dateTime(); # ... } # ... driver();which at least slightly segregates it. But perhaps there are better ways.
Again: I'm looking for the right way to do this, in terms of following best practices and Perl idioms. Performance is nice but readability and other needs take priority if I can't have everything.
hobbs ,
If you're using perl 5.10+, use astate
variable.use feature 'state'; # use 5.010; also works sub womble { state $foo = something_expensive(); return $foo ** 2; }will only call
something_expensive
once.If you need to work with older perls, then use a lexical variable in an outer scope with an extra pair of braces:
{ my $foo = something_expensive(); sub womble { return $foo ** 2; } }this keeps
$foo
from leaking to anyone except forwomble
.ikegami , 2012-05-31 21:14:04
Is there any interpolation in the pattern? If not, the pattern will only be compiled once no matter how many times the qr// is executed.$ perl -Mre=debug -e'qr/foo/ for 1..10' 2>&1 | grep Compiling | wc -l 1 $ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l 10Even if there is interpolation, the pattern will only be compiled if the interpolated variables have changed.
$ perl -Mre=debug -e'$x=123; qr/foo$x/ for 1..10;' 2>&1 | grep Compiling | wc -l 1 $ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l 10Otherwise, you can use
{ my $re = qr/.../; sub foo { ... /$re/ ... } }or
use feature qw( state ); sub foo { state $re = qr/.../; ... /$re/ ... }Alan Rocker , 2014-07-02 16:25:27
Regexes can be specified with the "o" modifier, which says "compile pattern once only" - in the 3rd. edition of the Camel, see p. 147zoul ,
There's a state keyword that might be a good fit for this situation:sub foo { state $regex = /.../; ... }TrueY , 2015-01-23 10:14:12
I would like to completeikegami
's great answer. Some more words I would like to waste on the definition of local variables in pre 5.10 perl .Let's see a simple example code:
#!/bin/env perl use strict; use warnings; { # local my $local = "After Crying"; sub show { print $local,"\n"; } } # local sub show2; show; show2; exit; { # local my $local = "Solaris"; sub show2 { print $local,"\n"; } } # localThe user would expect that both
sub
will print the local variable, but this is not true!Output:
After Crying Use of uninitialized value $local in print at ./x.pl line 20.The reason is that
show2
is parsed, but the initialization of the local variable is not executed! (Of course ifexit
is removed and ashow2
is added at the end,Solaris
will be printed in the thirds line)This can be fixed easily:
{ # local my $local; BEGIN { $local = "Solaris"; } sub show2 { print $local,"\n"; } } # localAnd now the output what was expected:
After Crying SolarisBut
state
in 5.10+ is a better choice...I hope this helps!
Nov 23, 2019 | ods.com.ua
CONTENTS
- What Is a Perl Module?
- Using Perl Modules: use vs. require
- The Sample Letter.pm Module
- Subroutines and Passing Parameters
- Another Sample Module: Finance
- Multiple Inheritance
- The Perl Module Libraries
- Summary
This chapter introduces you to the concepts behind references to Perl modules, packages, and classes. It also shows you how to create a few sample modules.
What Is a Perl Module?A Perl module is a set of Perl code that acts like a library of function calls. The term module in Perl is synonymous with the word package . Packages are a feature of Perl 4, whereas modules are prevalent in Perl 5.
You can keep all your reusable Perl code specific to a set of tasks in a Perl module. Therefore, all the functionality pertaining to one type of task is contained in one file. It's easier to build an application on these modular blocks. Hence, the word module applies a bit more than package .
Here's a quick introduction to modules. Certain topics in this section will be covered in detail throughout the rest of the book. Read the following paragraphs carefully to get an overview of what lies ahead as you write and use your own modules.
What is confusing is that the terms module and package are used interchangeably in all Perl documentation, and these two terms mean the very same thing . So when reading Perl documents, just think "package" when you see "module" and vice versa.
So, what's the premise for using modules? Well, modules are there to package (pardon the pun) variables, symbols, and interconnected data items together. For example, using global variables with very common names such as $k , $j , or $i in a program is generally not a good idea. Also, a loop counter, $i , should be allowed to work independently in two different portions of the code. Declaring $i as a global variable and then incrementing it from within a subroutine will create unmanageable problems with your application code because the subroutine may have been called from within a loop that also uses a variable called $i . The use of modules in Perl allows variables with the same name to be created at different, distinct places in the same program.
The symbols defined for your variables are stored in an associative array, referred to as a symbol table . These symbol tables are unique to a package. Therefore, variables of the same name in two different packages can have different values.
Each module has its own symbol table of all symbols that are declared within it. The symbol table basically isolates synonymous names in one module from another. The symbol table defines a namespace , that is, a space for independent variable names to exist in. Thus, the use of modules, each with its own symbol table, prevents a variable declared in one section from overwriting the values of other variables with the same name declared elsewhere in the same program.
As a matter of fact, all variables in Perl belong to a package. The variables in a Perl program belong to the main package. All other packages within a Perl program either are nested within this main package or exist at the same level. There are some truly global variables, such as the signal handler array %SIG , that are available to all other modules in an application program and cannot be isolated via namespaces. Only those variable identifiers starting with letters or an underscore are kept in a module's symbol table. All other symbols, such as the names STDIN , STDOUT , STDERR , ARGV , ARGVOUT , ENV , Inc , and SIG are forced to be in package _main.
Switching between packages affects only namespaces. All you are doing when you use one package or another is declaring which symbol table to use as the default symbol table for lookup of variable names. Only dynamic variables are affected by the use of symbol tables. Variables declared by the use of the my keyword are still resolved with the code block they happen to reside in and are not referenced through symbol tables. In fact, the scope of a package declaration remains active only within the code block it is declared in. Therefore, if you switch symbol tables by using a package within a subroutine, the original symbol table in effect when the call was made will be restored when the subroutine returns.
Switching symbol tables affects only the default lookup of dynamic variable names. You can still explicitly refer to variables, file handles, and so on in a specific package by prepending a packageName :: to the variable name. You saw what a package context was when using references in Chapter 3 . A package context simply implies the use of the symbol table by the Perl interpreter for resolving variable names in a program. By switching symbol tables, you are switching the package context.
Modules can be nested within other modules. The nested module can use the variables and functions of the module it is nested within. For nested modules, you would have to use moduleName :: nestedModuleName and so on. Using the double colon ( :: ) is synonymous with using a back quote ( ` ). However, the double colon is the preferred, future way of addressing variables within modules.
Explicit addressing of module variables is always done with a complete reference. For example, suppose you have a module, Investment , which is the default package in use, and you want to address another module, Bonds , which is nested within the Investment module. In this case, you cannot use Bond:: . Instead, you would have to use Investment::Bond:: to address variables and functions within the Bond module. Using Bond:: would imply the use of a package Bond that is nested within the main module and not within the Investment module.
The symbol table for a module is actually stored in an associative array of the module's names appended with two colons. The symbol table for a module called Bond will be referred to as the associative array %Bond:: . The name for the symbol table for the main module is %main:: , and can even be shortened to %:: . Similarly, all nested packages have their symbols stored in associative arrays with double colons separating each nesting level. For example, in the Bond module that is nested within the Investment module, the associative array for the symbols in the Bond module will be named %Investment::Bond:: .
A typeglob is really a global type for a symbol name. You can perform aliasing operations by assigning to a typeglob . One or more entries in an associative array for symbols will be used when an assignment via a typeglob is used. The actual value in each entry of the associative array is what you are referring to when you use the * variableName notation. Thus, there are two ways of referring to variable names in a package:
*Investment::money = *Investment::bills;$Investment::{'money'} = $Investment::{'bills'};
In the first method, you are referring to the variables via a typeglob reference. The use of the symbol table, %Investment:: , is implied here, and Perl will optimize the lookup for symbols money and bills . This is the faster and preferred way of addressing a symbol. The second method uses a lookup for the value of a variable addressed by 'money' and 'bills' in the associative array used for symbols, %Investment:: explicitly. This lookup would be done dynamically and will not be optimized by Perl. Therefore, the lookup will be forced to check the associative array every time the statement is executed. As a result, the second method is not efficient and should be used only for demonstration of how the symbol table is implemented internally.
Another example in this statement
*kamran = *husain;causes variables, subroutines, and file handles that are named via the symbol kamran to also be addressed via the symbol husain . That is, all symbol entries in the current symbol table with the key kamran will now contain references to those symbols addressed by the key husain . To prevent such a global assignment, you can use explicit references. For example, the following statement will let you address the contents of $husain via the variable $kamran :
*kamran = \$husain;However, any arrays such @kamran and @husain will not be the same. Only what the references specified explicitly will be changed. To summarize, when you assign one typeglob to another, you affect all the entries in a symbol table regardless of the type of variable being referred to. When you assign a reference from one variable type to another, you are only affecting one entry in the symbol table.
A Perl module file has the following format:
package ModuleName;
...
#### Insert module code ####
...
1;The filename has to be called ModuleName.pm . The name of a module must end in the string .pm by convention. The package statement is the first line of the file. The last line of the file must contain the line with the 1; statement. This in effect returns a true value to the application program using the module. Not using the 1; statement will not let the module be loaded correctly.
The package statement tells the Perl interpreter to start with a new namespace domain. Basically, all your variables in a Perl script belong to a package called main . Every variable in the main package can be referred to as $main'variable .
Here's the syntax for such references:
$packageName'variableNameThe single quote ( ' ) is synonymous with the double colon ( :: ) operator. I cover more uses of the :: operator in the next chapter. For the time being, you must remember that the following two statements are equivalent:
$packageName'variableName;
$packageName::variableName;The double-colon syntax is considered standard in the Perl world. Therefore, to preserve readability, I use the double-colon syntax in the rest of this book unless it's absolutely necessary to make exceptions to prove a point.
The default use of a variable name defers to the current package active at the time of compilation. Thus, if you are in the package Finance.pm and specify a variable $pv , the variable is actually equal to $Finance::$pv .
Using Perl Modules: use vs. requireYou include Perl modules in your program by using the use or the require statement. Here's the way to use either of these statements:
use ModuleName;
require ModuleName;Note that the .pm extension is not used in the code shown above. Also note that neither statement allows a file to be included more than once in a program. The returned value of true ( 1; ) as the last statement is required to let Perl know that a require d or use d module loaded correctly and lets the Perl interpreter ignore any reloads. In general, it's better to use the use Module; statement than the require Module; statement in a Perl program to remain compatible with future versions of Perl.
For modules, you might want to consider continuing to use the require statement. Here's why: The use statement does a little bit more work than the require statement in that it alters the namespace of the module that includes another module. You want this extra update of the namespace to be done in a program. However, when writing code for a module, you may not want the namespace to be altered unless it's explicitly required. In this event, you will use the require statement.
The require statement includes the full pathname of a file in the @Inc array so that the functions and variables in the module's file are in a known location during execution time. Therefore, the functions that are imported from a module are imported via an explicit module reference at runtime with the require statement. The use statement does the same thing as the require statement because it updates the @Inc array with full pathnames of loaded modules. The code for the use function also goes a step further and calls an import function in the module being use d to explicitly load the list of exported functions at compile time, thus saving the time required for an explicit resolution of a function name during execution.
Basically, the use statement is equivalent to
require ModuleName; import ModuleName [list of imported functions];The use of the use statement does change your program's namespace because the imported function names are inserted in the symbol table. The require statement does not alter your program's namespace. Therefore, the following statement
use ModuleName ();is equivalent to this statement:
require ModuleName;Functions are imported from a module via a call to a function called import . You can write your own import function in a module, or you can use the Exporter module and use its import function. In almost all cases, you will use the Exporter module to provide an import function instead of reinventing the wheel. (You'll learn more on this in the next section.) Should you decide not to use the Exporter module, you will have to write your own import function in each module that you write. It's much easier to simply use the Exporter module and let Perl do the work for you.
The Sample Letter.pm ModuleThe best way to illustrate the semantics of how a module is used in Perl is to write a simple module and show how to use it. Let's take the example of a local loan shark, Rudious Maximus, who is simply tired of typing the same "request for payment" letters. Being an avid fan of computers and Perl, Rudious takes the lazy programmer's approach and writes a Perl module to help him generate his memos and letters.
Now, instead of typing within fields in a memo template file, all he has to do is type a few lines to produce his nice, threatening note. Listing 4.1 shows you what he has to type.
Listing 4.1. Using the Letter module.
1 #!/usr/bin/perl -w
2 #
3 # Uncomment the line below to include the current dir in @Inc.
4 # push (@Inc, 'pwd');
5 #
6 use Letter;
7
8 Letter::To("Mr. Gambling Man","The money for Lucky Dog, Race 2");
9 Letter::ClaimMoneyNice();
10 Letter::ThankDem();
11 Letter::Finish();
The use Letter; statement is present to force the Perl interpreter to include the code for the module in the application program. The module should be located in the /usr/lib/perl5/ directory, or you can place it in any directory listed in the @Inc array. The @Inc array is the list of directories that the Perl interpreter will look for when attempting to load the code for the named module. The commented line (number 4) shows how to add the current working directory to include the path. The next four lines in the file generate the subject matter for the letter.
Here's the output from using the Letter module:
To: Mr. Gambling Man
Fm: Rudious Maximus, Loan Shark
Dt: Wed Feb 7 10:35:51 CST 1996Re: The money for Lucky Dog, Race 2
====================================================
It has come to my attention that your account is
way over due.
You gonna pay us soon?
Or would you like me to come ovah?Thanks for your support.
Sincerely,
RudiousThe Letter module file is shown in Listing 4.2. The name of the package is declared in the first line. Because this module's functions will be exported, I use the Exporter module. Therefore, the statement use Exporter; is required to inherit functionality from the Exporter module. Another required step is putting the word Exported in the @ISA array to allow searching for Exported.pm .
Note The @ISA array is a special array within each package. Each item in the array lists where else to look for a method if it cannot be found in the current package. The order in which packages are listed in the @ISA array is the order in which Perl searches for unresolved symbols. A class that is listed in the @ISA array is referred to as the base class of that particular class. Perl will cache missing methods found in base classes for future references. Modifying the @ISA array will flush the cache and cause Perl to look up all methods again.Let's now look at the code for Letter.pm in Listing 4.2.
Listing 4.2. The Letter.pm module.
1 package Letter;
2
3 require Exporter;
4 @ISA = (Exporter);
5
6 =head1 NAME
7
8 Letter - Sample module to generate letterhead for you
9
10 =head1 SYNOPSIS
11
12 use Letter;
13
14 Letter::Date();
15 Letter::To($name,$company,$address);
16
17 Then one of the following:
18 Letter::ClaimMoneyNice() {
19 Letter::ClaimMoney();
20 Letter::ThreatBreakLeg();
21
22 Letter::ThankDem();
23 Letter::Finish();
24
25 =head1 DESCRIPTION
26
27 This module provides a short example of generating a letter for a
28 friendly neighborbood loan shark.
29
30 The code begins after the "cut" statement.
31 =cut
32
33 @EXPORT = qw( Date,
34 To,
35 ClaimMoney,
36 ClaimMoneyNice,
37 ThankDem,
38 Finish );
39
40 #
41 # Print today's date
42 #
43 sub Letter::Date {
44 $date = 'date';
45 print "\n Today is $date";
46 }
47
48 sub Letter::To {
49 local($name) = shift;
50 local($subject) = shift;
51 print "\n To: $name";
52 print "\n Fm: Rudious Maximus, Loan Shark";
53 print "\n Dt: ", `date`;
54 print "\n Re: $subject";
55 print "\n\n";
56 print "\n====================================================\n";
57 }
58 sub Letter::ClaimMoney() {
59 print "\n You owe me money. Get your act together";
60 print "\n Do you want me to send Bruno over to ";
61 print "\n collect it , or are you gonna pay up?";
62 }
63
64 sub Letter::ClaimMoneyNice() {
65 print "\n It is come to my attention that your account is ";
66 print "\n way over due.";
67 print "\n You gonna pay us soon..";
68 print "\n or would you like me to come ovah?";
69 }
70
71 sub Letter::ThreatBreakLeg() {
72 print "\n apparently letters like these dont help";
73 print "\n I will have to make an example of you";
74 print "\n \n See you in the hospital, pal!";
75 }
76
77 sub Letter::ThankDem() {
78 print "\n\n Thanks for your support";
79 }
80
81 sub Letter::Finish(){
82 printf "\n\n\n\n Sincerely";
83 printf "\n Rudious \n ";
84 }
85
86 1;
Lines containing the equal sign are used for documentation. You must document each module for your own reference; Perl modules do not need to be documented, but it's a good idea to write a few lines about what your code does. A few years from now, you may forget what a module is about. Good documentation is always a must if you want to remember what you did in the past!
I cover documentation styles used for Perl in Chapter 8 , "Documenting Perl Scripts." For this sample module, the =head1 statement begins the documentation. Everything up to the =cut statement is ignored by the Perl interpreter.
Next, the module lists all the functions exported by this module in the @EXPORT array. The @EXPORT array defines all the function names that can be called by outside code. If you do not list a function in this @EXPORT array, it won't be seen by external code modules.
Following the @EXPORT array is the body of the code, one subroutine at a time. After all the subroutines are defined, the final statement 1; ends the module file. 1; must be the last executable line in the file.
Let's look at some of the functions defined in this module. The first function to look at is the simple Date function, lines 43 to 46, which prints the current UNIX date and time. There are no parameters to this function, and it doesn't return anything meaningful back to the caller.
Note the use of my before the $date variable in line 44. The my keyword is used to limit the scope of the variable to within the Date function's curly braces. Code between curly braces is referred to as a block . Variables declared within a block are limited in scope to within the curly braces. In 49 and 50, the local variables $name and $subject are visible to all functions.
You can also declare variables with the local qualifier. The use of local allows a variable to be in scope for the current block as well as for other blocks of code called from within this block. Thus, a local $x declared within one block is visible to all subsequent blocks called from within this block and can be referenced. In the following sample code, the ToTitled function's $name variable can be accessed but not the data in $iphone :
1 sub Letter::ToTitled {Subroutines and Passing Parameters
2 local($name) = shift;
3 my($phone) = shift;The sample code for Letter.pm showed how to extract one parameter at a time. The subroutine To() takes two parameters to set up the header for the memo.
Using functions within a module is not any different than using and defining Perl modules within the same code file. Parameters are passed by reference unless otherwise specified. Multiple arrays passed into a subroutine, if not explicitly dereferenced using the backslash, are concatenated.
The @_ input array in a function is always an array of scalar values. Passing values by reference is the preferred way in Perl to pass a large amount of data into a subroutine. ( See Chapter 3 , "References.")
Another Sample Module: FinanceThe Finance module, shown in Listing 4.3, is used to provide simple calculations for loan values. Using the Finance module is straightforward. All the functions are written with the same parameters, as shown in the formula for the functions.
Let's look at how the future value of an investment can be calculated. For example, if you invest some dollars, $pv , in a bond that offers a fixed percentage rate, $r , applied at known intervals for $n time periods, what is the value of the bond at the time of its expiration? In this case, you'll be using the following formula:
$fv = $pv * (1+$r) ** $n ;The function to get the future value is declared as FutureValue . Refer to Listing 4.3 to see how to use it.
Listing 4.3. Using the Finance module.
1 #!/usr/bin/perl -w
2
3 push(@Inc,'pwd');
4 use Finance;
5
6 $loan = 5000.00;
7 $apr = 3.5; # APR
8 $year = 10; # in years.
9
10 # ----------------------------------------------------------------
11 # Calculate the value at the end of the loan if interest
12 # is applied every year.
13 # ----------------------------------------------------------------
14 $time = $year;
15 $fv1 = Finance::FutureValue($loan,$apr,$time);
16 print "\n If interest is applied at end of year";
17 print "\n The future value for a loan of \$" . $loan . "\n";
18 print " at an APR of ", $apr , " for ", $time, " years";
19 printf " is %8.2f \n" , $fv1;
20
21 # ----------------------------------------------------------------
22 # Calculate the value at the end of the loan if interest
23 # is applied every month.
24 # ----------------------------------------------------------------
25 $rate = $apr / 12; # APR
26 $time = $year * 12; # in months
27 $fv2 = Finance::FutureValue($loan,$rate,$time);
28
29 print "\n If interest is applied at end of each month";
30 print "\n The future value for a loan of \$" . $loan . "\n";
31 print " at an APR of ", $apr , " for ", $time, " months";
32 printf " is %8.2f \n" , $fv2;
33
34 printf "\n The difference in value is %8.2f", $fv2 - $fv1;
35 printf "\n Therefore by applying interest at shorter time periods";
36 printf "\n we are actually getting more money in interest.\n";
Here is sample input and output of Listing 4.3.
$ testmeIf interest is applied at end of year
The future value for a loan of $5000
at an APR of 3.5 for 10 years is 7052.99If interest is applied at end of each month
The future value for a loan of $5000
at an APR of 3.5 for 120 months is 7091.72The difference in value is 38.73
Therefore by applying interest at shorter time periods
we are actually getting more money in interest.The revelation in the output is the result of the comparison of values between $fv1 and $fv2 . The $fv1 value is calculated with the application of interest once every year over the life of the bond. $fv2 is the value if the interest is applied every month at the equivalent monthly interest rate.
The Finance.pm package is shown in Listing 4.4 in its early development stages.
Listing 4.4. The Finance.pm package.
1 package Finance;
2
3 require Exporter;
4 @ISA = (Exporter);
5
6 =head1 Finance.pm
7
8 Financial Calculator - Financial calculations made easy with Perl
9
10 =head 2
11 use Finance;
12
13 $pv = 10000.0;
14
15 $rate = 12.5 / 12; # APR per month.
16
17 $time = 360 ; # months for loan to mature
18
19 $fv = FutureValue();
20
21 print $fv;
22
23 =cut
24
25 @EXPORT = qw( FutureValue,
26 PresentValue,
27 FVofAnnuity,
28 AnnuityOfFV,
29 getLastAverage,
30 getMovingAverage,
31 SetInterest);
32
33 #
34 # Globals, if any
35 #
36
37 local $defaultInterest = 5.0;
38
39 sub Finance::SetInterest($) {
40 my $rate = shift(@_);
41 $defaultInterest = $rate;
42 printf "\n \$defaultInterest = $rate";
43 }
44
45 # --------------------------------------------------------------------
46 # Notes:
47 # 1. The interest rate $r is given in a value of [0-100].
48 # 2. The $n given in the terms is the rate at which the interest
49 # is applied.
50 #
51 # --------------------------------------------------------------------
52
53 # --------------------------------------------------------------------
54 # Present value of an investment given
55 # fv - a future value
56 # r - rate per period
57 # n - number of period
58 # --------------------------------------------------------------------
59 sub Finance::FutureValue($$$) {
60 my ($pv,$r,$n) = @_;
61 my $fv = $pv * ((1 + ($r/100)) ** $n);
62 return $fv;
63 }
64
65 # --------------------------------------------------------------------
66 # Present value of an investment given
67 # fv - a future value
68 # r - rate per period
69 # n - number of period
70 # --------------------------------------------------------------------
71 sub Finance::PresentValue($$$) {
72 my $pv;
73 my ($fv,$r,$n) = @_;
74 $pv = $fv / ((1 + ($r/100)) ** $n);
75 return $pv;
76
77 }
78
79 # --------------------------------------------------------------------
80 # Get the future value of an annuity given
81 # mp - Monthly Payment of Annuity
82 # r - rate per period
83 # n - number of period
84 # --------------------------------------------------------------------
85
86 sub FVofAnnuity($$$) {
87 my $fv;
88 my $oneR;
89 my ($mp,$r,$n) = @_;
90
91 $oneR = ( 1 + $r) ** $n;
92 $fv = $mp * ( ($oneR - 1)/ $r);
93 return $fv;
94 }
95
96 # --------------------------------------------------------------------
97 # Get the annuity from the following bits of information
98 # r - rate per period
99 # n - number of period
100 # fv - Future Value
101 # --------------------------------------------------------------------
102
103 sub AnnuityOfFV($$$) {
104 my $mp; # mp - Monthly Payment of Annuity
105 my $oneR;
106 my ($fv,$r,$n) = @_;
107
108 $oneR = ( 1 + $r) ** $n;
109 $mp = $fv * ( $r/ ($oneR - 1));
110 return $mp;
111 }
112
113 # --------------------------------------------------------------------
114 # Get the average of the last "n" values in an array.
115 # --------------------------------------------------------------------
116 # The last $count number of elements from the array in @values
117 # The total number of elements in @values is in $number
118 #
119 sub getLastAverage($$@) {
120 my ($count, $number, @values) = @_;
121 my $i;
122
123 my $a = 0;
124 return 0 if ($count == 0);
125 for ($i = 0; $i< $count; $i++) {
126 $a += $values[$number - $i - 1];
127 }
128 return $a / $count;
129 }
130
131 # --------------------------------------------------------------------
132 # Get a moving average of the values.
133 # --------------------------------------------------------------------
134 # The window size is the first parameter, the number of items in the
135 # passed array is next. (This can easily be calculated within the
136 # function using the scalar() function, but the subroutine shown here
137 # is also being used to illustrate how to pass pointers.) The reference to the
138 # array of values is passed next, followed by a reference to the place
139 # the return values are to be stored.
140 #
141 sub getMovingAve($$\@\@) {
142 my ($count, $number, $values, $movingAve) = @_;
143 my $i;
144 my $a = 0;
145 my $v = 0;
146
147 return 0 if ($count == 0);
148 return -1 if ($count > $number);
149 return -2 if ($count < 2);
150
151 $$movingAve[0] = 0;
152 $$movingAve[$number - 1] = 0;
153 for ($i=0; $i<$count;$i++) {
154 $v = $$values[$i];
155 $a += $v / $count;
156 $$movingAve[$i] = 0;
157 }
158 for ($i=$count; $i<$number;$i++) {
159 $v = $$values[$i];
160 $a += $v / $count;
161 $v = $$values[$i - $count - 1];
162 $a -= $v / $count;
163 $$movingAve[$i] = $a;
164 }
165 return 0;
166 }
167
168 1;
Look at the declaration of the function FutureValue with ($$$) . The three dollar signs together signify three scalar numbers being passed into the function. This extra scoping is present for validating the type of the parameters passed into the function. If you were to pass a string instead of a number into the function, you would get a message very similar to this one:
Too many arguments for Finance::FutureValue at ./f4.pl line 15, near "$time)"
Execution of ./f4.pl aborted due to compilation errors.The use of prototypes when defining functions prevents you from sending in values other than what the function expects. Use @ or % to pass in an array of values. If you are passing by reference, use \@ or \% to show a scalar reference to an array or hash, respectively. If you do not use the backslash, all other types in the argument list prototype are ignored. Other types of disqualifiers include an ampersand for a reference to a function, an asterisk for any type, and a semicolon to indicate that all other parameters are optional.
Now, let's look at the lastMovingAverage function declaration, which specifies two integers in the front followed by an array. The way the arguments are used in the function is to assign a value to each of the two scalars, $count and $number , whereas everything else is sent to the array. Look at the function getMovingAverage() to see how two arrays are passed in order to get the moving average on a list of values.
The way to call the getMovingAverage function is shown in Listing 4.5.
Listing 4.5. Using the moving average function.
1 #!/usr/bin/perl -w
2
3 push(@Inc,'pwd');
4 use Finance;
5
6 @values = ( 12,22,23,24,21,23,24,23,23,21,29,27,26,28 );
7 @mv = (0);
8 $size = scalar(@values);
9 print "\n Values to work with = { @values } \n";
10 print " Number of values = $size \n";
11
12 # ----------------------------------------------------------------
13 # Calculate the average of the above function
14 # ----------------------------------------------------------------
15 $ave = Finance::getLastAverage(5,$size,@values);
16 print "\n Average of last 5 days = $ave \n";
17
18 Finance::getMovingAve(5,$size,@values,@mv);
19 print "\n Moving Average with 5 days window = \n { @mv } \n";
Here's the output from Listing 4.5:
Values to work with = { 12 22 23 24 21 23 24 23 23 21 29 27 26 28 }
Number of values = 14Average of last 5 days = 26.2
Moving Average with 5 days window =
{ 0 0 0 0 0 19.4 21.8 22 22 21.4 23 23.8 24.2 25.2 }The getMovingAverage() function takes two scalars and then two references to arrays as scalars. Within the function, the two scalars to the arrays are dereferenced for use as numeric arrays. The returned set of values is inserted in the area passed in as the second reference. Had the input parameters not been specified with \@ for each referenced array, the $movingAve array reference would have been empty and would have caused errors at runtime. In other words, the following declaration is not correct:
sub getMovingAve($$@@)The resulting spew of error messages from a bad function prototype is as follows:
Use of uninitialized value at Finance.pm line 128.
Use of uninitialized value at Finance.pm line 128.
Use of uninitialized value at Finance.pm line 128.
Use of uninitialized value at Finance.pm line 128.
Use of uninitialized value at Finance.pm line 128.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.
Use of uninitialized value at Finance.pm line 133.
Use of uninitialized value at Finance.pm line 135.Values to work with = { 12 22 23 24 21 23 24 23 23 21 29 27 26 28 }
Number of values = 14Average of last 5 days = 26.2
Moving Average with 5 days window =
{ 0 }This is obviously not the correct output. Therefore, it's critical that you pass by reference when sending more than one array.
Global variables for use within the package can also be declared. Look at the following segment of code from the Finance.pm module to see what the default value of the Interest variable would be if nothing was specified in the input. (The current module requires the interest to be passed in, but you can change this.)
Here's a little snippet of code that can be added to the end of the program shown in Listing 4.5 to add the ability to set interest rates.
20 local $defaultInterest = 5.0;
21 sub Finance::SetInterest($) {
22 my $rate = shift(@_);
23 $rate *= -1 if ($rate < 0);
24 $defaultInterest = $rate;
25 printf "\n \$defaultInterest = $rate";
26 }The local variable $defaultInterest is declared in line 20. The subroutine SetInterest to modify the rate is declared in lines 21 through 26. The $rate variable uses the values passed into the subroutine and simply assigns a positive value for it. You can always add more error checking if necessary.
To access the defaultInterest variable's value, you could define either a subroutine that returns the value or refer to the value directly with a call to the following in your application program:
$Finance::defaultInterest;Returned Values from Subroutines in a PackageThe variable holding the return value from the module function is declared as my variable . The scope of this variable is within the curly braces of the function only. When the called subroutine returns, the reference to my variable is returned. If the calling program uses this returned reference somewhere, the link counter on the variable is not zero; therefore, the storage area containing the returned values is not freed to the memory pool. Thus, the function that declares
my $pvand then later returns the value of $pv returns a reference to the value stored at that location. If the calling routine performs a call like this one:
Finance::FVofAnnuity($monthly,$rate,$time);there is no variable specified here into which Perl stores the returned reference; therefore, any returned value (or a list of values) is destroyed. Instead, the call with the returned value assigned to a local variable, such as this one:
$fv = Finance::FVofAnnuity($monthly,$rate,$time);maintains the variable with the value. Consider the example shown in Listing 4.6, which manipulates values returned by functions.
Listing 4.6. Sample usage of the my function.
1 #!/usr/bin/perl -w
2
3 push(@Inc,'pwd');
4 use Finance;
5
6 $monthly = 400;
7 $rate = 0.2; # i.e. 6 % APR
8 $time = 36; # in months
9
10 print "\n# ------------------------------------------------";
11 $fv = Finance::FVofAnnuity($monthly,$rate,$time);
12 printf "\n For a monthly %8.2f at a rate of %%%6.2f for %d periods",
13 $monthly, $rate, $time;
14 printf "\n you get a future value of %8.2f ", $fv;
15
16 $fv *= 1.1; # allow 10 % gain in the house value.
17
18 $mo = Finance::AnnuityOfFV($fv,$rate,$time);
19
20 printf "\n To get 10 percent more at the end, i.e. %8.2f",$fv;
21 printf "\n you need a monthly payment value of %8.2f",$mo,$fv;
22
23 print "\n# ------------------------------------------------ \n";
Here is sample input and output for this function:
$ testmeMultiple Inheritance
# ------------------------------------------------
For a monthly 400.00 at a rate of % 0.20 for 36 periods
you get a future value of 1415603.75
To get 10 percent more at the end, i.e. 1557164.12
you need a monthly payment value of 440.00
# ------------------------------------------------Modules implement classes in a Perl program that uses the object-oriented features of Perl. Included in object-oriented features is the concept of inheritance . (You'll learn more on the object-oriented features of Perl in Chapter 5 , "Object-Oriented Programming in Perl .") Inheritance means the process with which a module inherits the functions from its base classes. A module that is nested within another module inherits its parent modules' functions. So inheritance in Perl is accomplished with the :: construct. Here's the basic syntax:
SuperClass::NextSubClass:: ... ::ThisClass.The file for these is stored in ./SuperClass/NextSubClass/ . Each double colon indicates a lower-level directory in which to look for the module. Each module, in turn, declares itself as a package with statements like the following:
package SuperClass::NextSubClass;
package SuperClass::NextSubClass::EvenLower;For example, say that you really want to create a Money class with two subclasses, Stocks and Finance . Here's how to structure the hierarchy, assuming you are in the /usr/lib/perl5 directory:
- Create a Money directory under the /usr/lib/perl5 directory.
- Copy the existing Finance.pm file into the Money subdirectory.
- Create the new Stocks.pm file in the Money subdirectory.
- Edit the Finance.pm file to use the line package Money::Finance instead of package Finance; .
- Edit scripts to use Money::Finance as the subroutine prefix instead of Finance:: .
- Create a Money.pm file in the /usr/lib/perl5 directory.
The Perl script that gets the moving average for a series of numbers is presented in Listing 4.7.
Listing 4.7. Using inheriting modules.
1 #!/usr/bin/perl -w
2 $aa = 'pwd';
3 $aa .= "/Money";
4 push(@Inc,$aa);
5 use Money::Finance;
6 @values = ( 12,22,23,24,21,23,24,23,23,21,29,27,26,28 );
7 @mv = (0);
8 $size = scalar(@values);
9 print "\n Values to work with = { @values } \n";
10 print " Number of values = $size \n";
11 # ----------------------------------------------------------------
12 # Calculate the average of the above function
13 # ----------------------------------------------------------------
14 $ave = Money::Finance::getLastAverage(5,$size,@values);
15 print "\n Average of last 5 days = $ave \n";
16 Money::Finance::getMovingAve(5,$size,@values,@mv);
17 # foreach $i (@values) {
18 # print "\n Moving with 5 days window = $mv[$i] \n";
19 # }
20 print "\n Moving Average with 5 days window = \n { @mv } \n";
Lines 2 through 4 add the path to the Money subdirectory. The use statement in line 5 now addresses the Finance.pm file in the ./Money subdirectory. The calls to the functions within Finance.pm are now called with the prefix Money::Finance:: instead of Finance:: . Therefore, a new subdirectory is shown via the :: symbol when Perl is searching for modules to load.
The Money.pm file is not required. Even so, you should create a template for future use. Actually, the file would be required to put any special requirements for initialization that the entire hierarchy of modules uses. The code for initialization is placed in the BEGIN() function. The sample Money.pm file is shown in Listing 4.8.
Listing 4.8. The superclass module for Finance.pm .
1 package Money;
2 require Exporter;
3
4 BEGIN {
5 printf "\n Hello! Zipping into existence for you\n";
6 }
7 1;
To see the line of output from the printf statement in line 5, you have to insert the following commands at the beginning of your Perl script:
use Money;
use Money::Finance;To use the functions in the Stocks.pm module, you use this line:
use Money::Stocks;The Stocks.pm file appears in the Money subdirectory and is defined in the same format as the Finance.pm file, with the exceptions that use Stocks is used instead of use Finance and the set of functions to export is different.
The Perl Module LibrariesA number of modules are included in the Perl distribution. Check the /usr/lib/perl5/lib directory for a complete listing after you install Perl. There are two kinds of modules you should know about and look for in your Perl 5 release, Pragmatic and Standard modules.
Pragmatic modules, which are also like pragmas in C compiler directives, tend to affect the compilation of your program. They are similar in operation to the preprocessor elements of a C program. Pragmas are locally scoped so that they can be turned off with the no command. Thus, the command
no POSIX ;turns off the POSIX features in the script. These features can be turned back on with the use statement.
Standard modules bundled with the Perl package include several functioning packages of code for you to use. Refer to appendix B, "Perl Module Archives," for a complete list of these standard modules.
To find out all the .pm modules installed on your system, issue the following command. (If you get an error, add the /usr/lib/perl5 directory to your path.)
find /usr/lib/perl5 -name perl "*.pm" -printExtension ModulesExtension modules are written in C (or a mixture of Perl and C) and are dynamically loaded into Perl if and when you need them. These types of modules for dynamic loading require support in the kernel. Solaris lets you use these modules. For a Linux machine, check the installation pages on how to upgrade to the ELF format binaries for your Linux kernel.
What Is CPAN?The term CPAN (Comprehensive Perl Archive Network) refers to all the hosts containing copies of sets of data, documents, and Perl modules on the Net. To find out about the CPAN site nearest you, search on the keyword CPAN in search engines such as Yahoo!, AltaVista, or Magellan. A good place to start is the www.metronet.com site .
SummaryThis chapter introduced you to Perl 5 modules and described what they have to offer. A more comprehensive list is found on the Internet via the addresses shown in the Web sites http://www.metronet.com and http://www.perl.com .
A Perl package is a set of Perl code that looks like a library file. A Perl module is a package that is defined in a library file of the same name. A module is designed to be reusable. You can do some type checking with Perl function prototypes to see whether parameters are being passed correctly. A module has to export its functions with the @EXPORT array and therefore requires the Exporter module. Modules are searched for in the directories listed in the @Inc array.
Obviously, there is a lot more to writing modules for Perl than what is shown in this chapter. The simple examples in this chapter show you how to get started with Perl modules. In the rest of the book I cover the modules and their features, so hang in there.
I cover Perl objects, classes, and related concepts in Chapter 5 .
Nov 23, 2019 | perlmaven.com
List::Util module provides a number of simple and some more complex functions that can be used on lists, anything that returns a list anything that can be seen as a list.For example these can be used on arrays as they "return their content" in list context . min
If given a list of numbers to it, it will return the smallest number:
examples/min.pl
- use 5.010 ;
- use strict ;
- use warnings ;
- use List :: Util qw ( min );
- say min ( 10 , 3 , - 8 , 21 ); # -8
- my @prices = ( 17.2 , 23.6 , 5.50 , 74 , '10.3' );
- say min ( @prices ); # 5.5
- # Argument "2x" isn't numeric in subroutine entry at examples/min.pl line 14.
- say min ( 10 , 3 , '2x' , 21 ); # 2
If one of the arguments is a string that cannot be fully converted to a number automatically and if you have use warnings on as you should , then you'll see the following warnings: Argument ... isn't numeric in subroutine entry at ...
minstrThere is a corresponding function called minstr that will accept strings and sort them according to the ASCII order, though I guess it will work with Unicode as well if that's what you are feeding it.
examples/minstr.pl
- use 5.010 ;
- use strict ;
- use warnings ;
- use List :: Util qw ( minstr );
- say minstr ( 'f' , 'b' , 'e' ); # b
It can also accept numbers as parameters and will treat them as strings. The result might surprise you, if you are not familiar with the automatic number to string conversion of Perl, and that the string "11" is ahead of the string "2" because the comparison works character-by-character and in this case the first character of "11" is ahead of the first (and only) character of "2" in the ASCII table.
examples/minstr_numbers.pl
- use 5.010 ;
- use strict ;
- use warnings ;
- use List :: Util qw ( minstr );
- say minstr ( 2 , 11 , 99 ); # 11
After all internally it uses the lt operator.
maxSimilar to min just returns the biggest number.
maxstrSimilar to minstr , returns the biggest string in ASCII order.
sumThe sum function adds up the provided numbers and returns their sum. If one or more of the values provided is a string that cannot be fully converted to a number it will generate a warning like this: Argument ... isn't numeric in subroutine entry at ... . If the parameters of sum are empty the function returns undef . This is unfortunate as it should be 0, but in order to provide backwards compatibility, if the provided list is empty then undef is returned.
examples/sum.pl
sum0
- use 5.010 ;
- use strict ;
- use warnings ;
- use List :: Util qw ( sum );
- say sum ( 10 , 3 , - 8 , 21 ); # 26
- my @prices = ( 17.2 , 23.6 , '1.1' );
- say sum ( @prices ); # 41.9
- my @empty ;
- # Use of uninitialized value in say at examples/sum.pl line 14.
- say sum ( @empty ); # (prints nothing)
In order to fix the above issue, that sum() return undef , in version 1.26 of the module, in 2012, a new function called sum0 was introduced that behaves exactly like the sum function, but returns 0 if no values was supplied.
examples/sum0.pl
product
- use 5.010 ;
- use strict ;
- use warnings ;
- use List :: Util qw ( sum0 );
- say sum0 ( 10 , 3 , - 8 , 21 ); # 26
- my @prices = ( 17.2 , 23.6 , '1.1' );
- say sum0 ( @prices ); # 41.9
- my @empty ;
- say sum0 ( @empty ); # 0
The product function multiplies its parameters. As this function is newer it was not constrained with backward compatibility issues so if the provided list is empty, the returned value will be 1.
examples/product.pl
Other functions of List::Util
- use 5.010 ;
- use strict ;
- use warnings ;
- use List :: Util qw ( product );
- my @interest = ( 1.2 , 2.6 , 4 , '1.3' );
- say product ( @interest ); # 16.224
- my @empty ;
- say product ( @empty ); # 1
The module has a number of other functions that were used in various other articles:
firstfirst returns the first element from a list that satisfies the given condition. For examples on how to use it an why is it good check out the articles Fast lookup by name or by date - Array - Hash - Linked List and Search for hash in an array of hashes .
anyThe any function will return true if any of the given values satisfies the given condition. It is shown in the article Filtering values using Perl grep as a better solution.
It is also used in the example showing how to create a testing module and how to implement 'is_any' to test multiple expected values .
allThe all function will return true if all the supplied values satisfy the given condition. It can be seen in the article Check several regexes on many strings .
reduceThe reduce function might be familiar to you from the MapReduce programming model that was lauded around "BigData". It makes it provides a way to summarize data in an easy way. Implementing factorial in Perl - n! is a good and simple example. It is also used in the Fast lookup by name or by date - Array - Hash - Linked List article.
Nov 21, 2019 | tux.nl
Why my style is best better
I will try to explain the logic behind the style decisions taken over that last 35+ years of programming in different languages.
About programming style and layout there are as many opinions as there are people. Most important in my opinion is to think about the reasoning behind what you, your team or your company chooses to follow as guides.
I seriously think that way too many (young) programmers leave school, brainwashed with GNU-style coding without realizing that the amount of indentation and the placing of braces, brackets and parentheses were well thought about.
Several well known styles (including mine) are discussed at wikimedia . It is worth reading through them to see the pros and cons of each.
For me personally, the GNU coding style is one of the reasons I do NOT contribute a lot to these projects. The style does not fit my logic, and if I send patches that are rejected simply because I wrote them in a style/layout that I think is way better because I then understand the underlying logic, I give up.
Here I will take a tour through what I think is the only correct way of (perl) code layout, and why. Most of this can be achieved with Perl::Tidy and a correct .perltidyrc . I'll use their configuration definitions as a guide.
- Indentation in code blocks
- Opening Block Brace Right or Left
- Braces Left
- Because braces are just syntactic sugar to keep a block together, it should visually also bind to the block, and not to the conditional. As the closing brace - or
END
in languages like PASCAL - is visually showing me the end of the block, it should obviously have the same indent as the block itself. An advantage is that the alignment of the closing brace with the block emphasizes the fact that the entire block is conceptually (as well as programmatically) a single compound statement.
In other words: I see the braces being part of the block, and as all statements inside a block share the same indentation, in my opinion the brace - being part of the block - should have the same indentation too.
- Indent width is 4, tabs are allowed (when set to 8). I prefer having it being spaces only, but as I cannot see the difference with good editors, I do not really care.
- Opening brace should be on the same line as the conditional
- Block should be indented
- Closing brace should have the same indent as the block
if ($flag eq "a") { $anchor = $header; }This style is also referred to as Ratliff style on wikipedia or Banner style on wikimedia.- Continuation Indentation
if ($flag eq "a") { $anchor = substr ($header, 0, 6) . substr ($char_list, $place_1, 1) . substr ($char_list, $place_2, 1); }- Or, also acceptable:
if ($flag eq "a") { $anchor = substr ($header, 0, 6) . substr ($char_list, $place_1, 1) . substr ($char_list, $place_2, 1); }- Braces Right
if ($bigwasteofspace1 && $bigwasteofspace2 || $bigwasteofspace3 && $bigwasteofspace4) { big_waste_of_time (); }- also acceptable:
if ( $bigwasteofspace1 && $bigwasteofspace2 || $bigwasteofspace3 && $bigwasteofspace4) { big_waste_of_time (); }- also acceptable:
if ( $bigwasteofspace1 && $bigwasteofspace2 || $bigwasteofspace3 && $bigwasteofspace4) { big_waste_of_time (); }- (No) Cuddled Else
- Of course cuddled else is not the way to go, as it makes removing either branch more difficult and makes the indent of the closing brace go wrong. The only right way to use if/else indent is uncuddled:
if ($flag eq "h") { $headers = 0; } elsif ($flag eq "f") { $sectiontype = 3; } else { print "invalid option: " . substr ($arg, $i, 1) . "\n"; dohelp (); }- Vertical tightness
sub _directives { { ENDIF => \&_endif, IF => \&_if, }; } # _directivesthe opening brace of a sub may optionally be put on a new line. If so, it should be in column one, for all those that use 'vi' or one of it's clones, so }, {, ]], and [[ work as expected.
if the opening brace is on the same line, which I prefer, it requires a single leading spacesub _directives { { ENDIF => \&_endif, IF => \&_if, }; } # _directives- Indentation Style for Other Containers
- Opening Vertical Tightness
$dbh = DBI->connect (undef, undef, undef, { PrintError => 0, RaiseError => 1, }); if (!defined (start_slip ($DEVICE, $PHONE, $ACCOUNT, $PASSWORD, $LOCAL, $REMOTE, $NETMASK, $MTU)) && $continuation_flag) { do_something_about_it (); }- Closing Token Placement
my @month_of_year = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", );- also acceptable:
my @month_of_year = (qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ));As with the closing brace of a block, the closing parenthesis belongs to the data in the container it closes, and thus should have the same indentation.- Define Horizontal Tightness
- Of course
function <space> <paren> <no-space> <first-arg> <comma> <space>
if ((my $duration = travel ($target, $means)) > 1200) {One of my pet-peeves. Having white-space between the function name and its opening parenthesis is the best match to how we think. As an example, if I would ask someone to describe his/her day, he/she might answerI woke up I freshened myself I had breakfast I got to work I worked I had lunch I worked again I went home I had diner I watched TV I brushed my teeth I went to bedIn computer-speakwake_up (); wash ($self); eat ("breakfast"); goto ("work") work (); eat ("lunch"); work (); goto ("home"); eat ("diner"); watch_tv (); wash ($teeth); sleep ();In which the seasoned programmer might seefor $day in (qw( Mon Tue Wed Thu Fri )) { wake_up (); wash ($self); eat ("breakfast"); : :Or, more extreme to show the sequence of actionsfor $day in (qw( Mon Tue Wed Thu Fri )) { wake_up (); wash ($self); eat ("breakfast"); : :Where it, IMHO, clearly shows that the actions are far more important than what it takes to perform the action. When I read through the process, I don't care about what transport the person uses to get to work and if eggs are part of the breakfast. These are the parameters to the actionsfor $day in (qw( Mon Tue Wed Thu Fri )) { wake_up (); wash ($day eq "Fri" ? "bath" : "shower", water_temp => "47"); eat (type => "breakfast", eggs => 2, toast => 4, Tea => "yes"); travel (target => $work, means => "train"); : :I will only have a look at the function's argument if I need to. In reading that Ieat
, I see what action is taken. That's enough for understanding the program flow. The arguments to the function have to be grouped together using parenthesis for the function to know that all the arguments are for the function: the parenthesis are there to group the arguments, not to make the function a function so the parenthesis belong to the arguments and not to the function and therefor are to be close to the arguments ant not to the function.
Arguments are separated by a comma and a space, just to separate the arguments more for better readabilitymy $width = $col[$j + $k] - $col[$j]; my %bf = map { $_ => -M $_ } grep { m/\.deb$/ } dirents ".";- Statement modifiers
$work_done and go_home ();A rule of thumb is to NEVER use statement modifiers likego_home () unless $work_done; # WRONG!As it will draw the attention to going home (unconditionally) instead of to the condition, which is more important. This is especially annoying when using exit, die, croak or return. Any of these will visually end the current scope, so you do not have to read on. Unless there is a statement modifier and you need to re-read the entire section.- No else after return/exit/die/croak/throw
if (expression) { return; } else { return 42; }As any of return, exit, die, croak, or throw will immediately exit the current scope, the mind will read the code as to stop processing it right there, which is exactly what those keywords are for.
In an if/else construct, the code after the construct is supposed to be executed when either if the if/else branches where followed. If the if-branch exits the current scope, there is no need to run the code after the construct, so the else is useless.
This is the main reason why these keywords should never have a statement modifier (and no, you cannot come up with a valid exception to this rule).- Statement Termination Semicolon Spaces
my $i = 1;- For Loop Semicolon Spaces
for (@a = @$ap, $u = shift @a; @a; $u = $v) {- Block Comment Indentation
- If comment is aligned to the left margin, leave it there
- If the original comment was indented, match the indent to the surrounding code.
- Never reformat comments itself. Do not wrap
- Outdenting Long Quotes
if ($source_stream) { if (@ARGV > 0) { die "You may not specify any filenames when a source array is given\n"; } } if ($source_stream) { if (@ARGV > 0) { die "You may not specify any filenames ". "when a source array is given\n"; } } for (@methods) { push @results, { name => $_->name, help => $_->help, }; }
Nov 21, 2019 | perlmonks.org
LanX (Archbishop) on Nov 20, 2019 at 15:59 UTC
Re: Replaying debugger commands from historySure!
Have a look at the docs in perldebug#Debugger-Customization concerning
@DB::typeahead
like
sub afterinit { push @DB::typeahead, "b 4", "b 6"; }
IIRC it should be either settable
- in .perldb
- or in the -e'' command line option at startup
- (update) or even inside your debugged code inside BEGIN
Nov 21, 2019 | stackoverflow.com
Ask Question Asked 8 years, 5 months ago Active 6 years ago Viewed 941 times 10 2
eli ,Jun 7, 2018 at 14:13
I work quit a bit with lib ReadLine and the lib Perl Readline.Yet, the Perl debugger refuses to save the session command line history.
Thus, each time I invoke the debugger I lose all of my previous history.
Does anyone know how to have the Perl debugger save, and hopefully, append session history similar to the bash
HISTORYFILE
?mirod ,Jun 22, 2011 at 10:31
The way I do this is by having the following line in my~/.perldb
file:
&parse_options("HistFile=$ENV{HOME}/.perldb.hist");
Debugger commands are then stored in
~/.perldb.hist
and accessible across sessions.ysth ,Jul 13, 2011 at 9:37
Addparse_options("TTY=/dev/stdin ReadLine=0");
to .perldb, then:rlwrap -H .perl_history perl -d ...mephinet ,Feb 21, 2012 at 12:37
$ export PERLDB_OPTS=HistFile=$HOME/.perldb.history,
I did the following:1) Created
~/.perldb
, which did not exist previously.2) Added
&parse_options("HistFile=$ENV{HOME}/.perldb.hist");
from mirod's answer.3) Added
export PERLDB_OPTS=HistFile=$HOME/.perldb.history
to ~/.bashrc from mephinet's answer.4) Ran
source .bashrc
5) Ran
perl -d my program.pl
, and got this warning/errorperldb: Must not source insecure rcfile /home/ics/.perldb. You or the superuser must be the owner, and it must not be writable by anyone but its owner.6) I protected
~/.perldb
with owner rwchmod 700 ~/.perldb
, and the error went away.
Nov 21, 2019 | perlmonks.org
This code was written as a solution to the problem posed in Search for identical substrings . As best I can tell it runs about 3 million times faster than the original code.
The code reads a series of strings and searches them for the longest substring between any pair of strings. In the original problem there were 300 strings about 3K long each. A test set comprising 6 strings was used to test the code with the result given below.
Someone with Perl module creation and publication experience could wrap this up and publish it if they wish.
use strict; use warnings; use Time::HiRes; use List::Util qw(min max); my $allLCS = 1; my $subStrSize = 8; # Determines minimum match length. Should be a power of 2 # and less than half the minimum interesting match length. The larger this value # the faster the search runs. if (@ARGV != 1) { print "Finds longest matching substring between any pair of test strings\n"; print "the given file. Pairs of lines are expected with the first of a\n"; print "pair being the string name and the second the test string."; exit (1); } # Read in the strings my @strings; while () { chomp; my $strName = $_; $_ = ; chomp; push @strings, [$strName, $_]; } my $lastStr = @strings - 1; my @bestMatches = [(0, 0, 0, 0, 0)]; # Best match details my $longest = 0; # Best match length so far (unexpanded) my $startTime = [Time::HiRes::gettimeofday ()]; # Do the search for (0..$lastStr) { my $curStr = $_; my @subStrs; my $source = $strings[$curStr][1]; my $sourceName = $strings[$curStr][0]; for (my $i = 0; $i 0; push @localBests, [@test] if $dm >= 0; $offset = $test[3] + $test[4]; next if $test[4] 0; push @bestMatches, [@test]; } continue {++$offset;} } next if ! $allLCS; if (! @localBests) { print "Didn't find LCS for $sourceName and $targetName\n"; next; } for (@localBests) { my @curr = @$_; printf "%03d:%03d L[%4d] (%4d %4d)\n", $curr[0], $curr[1], $curr[4], $curr[2], $curr[3]; } } } print "Completed in " . Time::HiRes::tv_interval ($startTime) . "\n"; for (@bestMatches) { my @curr = @$_; printf "Best match: %s - %s. %d characters starting at %d and %d.\n", $strings[$curr[0]][0], $strings[$curr[1]][0], $curr[4], $curr[2], $curr[3]; } sub expandMatch { my ($index1, $index2, $str1Start, $str2Start, $matchLen) = @_; my $maxMatch = max (0, min ($str1Start, $subStrSize + 10, $str2Start)); my $matchStr1 = substr ($strings[$index1][1], $str1Start - $maxMatch, $maxMatch); my $matchStr2 = substr ($strings[$index2][1], $str2Start - $maxMatch, $maxMatch); ($matchStr1 ^ $matchStr2) =~ /\0*$/; my $adj = $+[0] - $-[0]; $matchLen += $adj; $str1Start -= $adj; $str2Start -= $adj; return ($index1, $index2, $str1Start, $str2Start, $matchLen); }Output using bioMan 's six string sample:
Completed in 0.010486 Best match: >string 1 - >string 3 . 1271 characters starting at 82 an + d 82. [download]
Nov 15, 2019 | www.quora.com
Why are Unix system administrators still using Perl for scripting when they could use Python? Update Cancel
a OYLu d zEv ORPC b dRl y q nyXNY D AZ a eSr t gpl a yTipB d lH o xE g ookz H Tr Q voRm . iKPKM c YuOhH o M m HVViy Visualize Docker performance and usage in real time. Track Docker health and usage alongside custom metrics from your apps and services. Try Datadog for free. Learn More You dismissed this ad. The feedback you provide will help us show you more relevant content in the future. Undo Answer Wiki 12 Answers
Joshua Day , Currently developing reporting and testing tools for linux Updated Apr 26 · Author has 83 answers and 71k answer views
There are several reasons and ill try to name a few.
- Perl syntax and semantics closely resembles shell languages that are part of core Unix systems like sed, awk, and bash. Of these languages at least bash knowledge is required to administer a Unix system anyway.
- Perl was designed to replace or improve the shell languages in Unix/linux by combining all their best features into a single language whereby an administrator can write a complex script with a single language instead of 3 languages. It was essentially designed for Unix/linux system administration.
- Perl regular expressions (text manipulation) were modeled off of sed and then drastically improved upon to the extent that subsequent languages like python have borrowed the syntax because of just how powerful it is. This is infinitely powerful on a unix system because the entire OS is controlled using textual data and files. No other language ever devised has implemented regular expressions as gracefully as perl and that includes the beloved python. Only in perl is regex integrated with such natural syntax.
- Perl typically comes preinstalled on Unix and linux systems and is practically considered part of the collection of softwares that define such a system.
- Thousands of apps written for Unix and linux utilize the unique properties of this language to accomplish any number of tasks. A Unix/linux sysadmin must be somewhat familiar with perl to be effective at all. To remove the language would take considerable effort for most systems to the extent that it's not practical.. Therefore with regard to this environment Perl will remain for years to come.
- Perl's module archive called CPAN already contains a massive quantity of modules geared directly for unix systems. If you use Perl for your administration tasks you can capitalize on these modules. These are not newly written and untested modules. These libraries have been controlling Unix systems for 20 years reliably and the pinnacle of stability in Unix systems running across the world.
- Perl is particularly good at glueing other software together. It can take the output of one application and manipulate it into a format that is easily consumable by another, mostly due to its simplistic text manipulation syntax. This has made Perl the number 1 glue language in the world. There are millions of softwares around the world that are talking to each other even though they were not designed to do so. This is in large part because of Perl. This particular niche will probably decline as standardization of interchange formats and APIs improves but it will never go away.
I hope this helps you understand why perl is so prominent for Unix administrators. These features may not seem so obviously valuable on windows systems and the like. However on Unix systems this language comes alive like no other.
Nov 15, 2019 | www.quora.com
Daniel Korenblum , works at Bayes Impact Updated May 25, 2015 There are many reasons why non-OOP languages and paradigms/practices are on the rise, contributing to the relative decline of OOP.
First off, there are a few things about OOP that many people don't like, which makes them interested in learning and using other approaches. Below are some references from the OOP wiki article:
taken from:
- Cardelli, Luca (1996). "Bad Engineering Properties of Object-Oriented Languages". ACM Comput. Surv. (ACM) 28 (4es): 150. doi:10.1145/242224.242415. ISSN 0360-0300. Retrieved 21 April 2010.
- Armstrong, Joe. In Coders at Work: Reflections on the Craft of Programming. Peter Seibel, ed. Codersatwork.com , Accessed 13 November 2009.
- Stepanov, Alexander. "STLport: An Interview with A. Stepanov". Retrieved 21 April 2010.
- Rich Hickey, JVM Languages Summit 2009 keynote, Are We There Yet? November 2009. (edited)
Also see this post and discussion on hackernews:
Object Oriented Programming is an expensive disaster which must end
One of the comments therein linked a few other good wikipedia articles which also provide relevant discussion on increasingly-popular alternatives to OOP:
- Modularity and design-by-contract are better implemented by module systems ( Standard ML )
- Encapsulation is better served by lexical scope ( http://en.wikipedia.org/wiki/Sco... )
- Data is better modelled by algebraic datatypes ( Algebraic data type )
- Type-checking is better performed structurally ( Structural type system )
- Polymorphism is better handled by first-class functions ( First-class function ) and parametricity ( Parametric polymorphism )
Personally, I sometimes think that OOP is a bit like an antique car. Sure, it has a bigger engine and fins and lots of chrome etc., it's fun to drive around, and it does look pretty. It is good for some applications, all kidding aside. The real question is not whether it's useful or not, but for how many projects?When I'm done building an OOP application, it's like a large and elaborate structure. Changing the way objects are connected and organized can be hard, and the design choices of the past tend to become "frozen" or locked in place for all future times. Is this the best choice for every application? Probably not.
If you want to drive 500-5000 miles a week in a car that you can fix yourself without special ordering any parts, it's probably better to go with a Honda or something more easily adaptable than an antique vehicle-with-fins.
Finally, the best example is the growth of JavaScript as a language (officially called EcmaScript now?). Although JavaScript/EcmaScript (JS/ES) is not a pure functional programming language, it is much more "functional" than "OOP" in its design. JS/ES was the first mainstream language to promote the use of functional programming concepts such as higher-order functions, currying, and monads.
The recent growth of the JS/ES open-source community has not only been impressive in its extent but also unexpected from the standpoint of many established programmers. This is partly evidenced by the overwhelming number of active repositories on Github using JavaScript/EcmaScript:
Top Github Languages of 2014 (So far)
Because JS/ES treats both functions and objects as structs/hashes, it encourages us to blur the line dividing them in our minds. This is a division that many other languages impose - "there are functions and there are objects/variables, and they are different".
This seemingly minor (and often confusing) design choice enables a lot of flexibility and power. In part this seemingly tiny detail has enabled JS/ES to achieve its meteoric growth between 2005-2015.
This partially explains the rise of JS/ES and the corresponding relative decline of OOP. OOP had become a "standard" or "fixed" way of doing things for a while, and there will probably always be a time and place for OOP. But as programmers we should avoid getting too stuck in one way of thinking / doing things, because different applications may require different approaches.
Above and beyond the OOP-vs-non-OOP debate, one of our main goals as engineers should be custom-tailoring our designs by skillfully choosing the most appropriate programming paradigm(s) for each distinct type of application, in order to maximize the "bang for the buck" that our software provides.
Although this is something most engineers can agree on, we still have a long way to go until we reach some sort of consensus about how best to teach and hone these skills. This is not only a challenge for us as programmers today, but also a huge opportunity for the next generation of educators to create better guidelines and best practices than the current OOP-centric pedagogical system.
Here are a couple of good books that elaborates on these ideas and techniques in more detail. They are free-to-read online:
Mike MacHenry , software engineer, improv comedian, maker Answered Feb 14, 2015 · Author has 286 answers and 513.7k answer views Because the phrase itself was over hyped to an extrodinary degree. Then as is common with over hyped things many other things took on that phrase as a name. Then people got confused and stopped calling what they are don't OOP.Yes I think OOP ( the phrase ) is on the decline because people are becoming more educated about the topic.
It's like, artificial intelligence, now that I think about it. There aren't many people these days that say they do AI to anyone but the laymen. They would say they do machine learning or natural language processing or something else. These are fields that the vastly over hyped and really nebulous term AI used to describe but then AI ( the term ) experienced a sharp decline while these very concrete fields continued to flourish.
Nov 05, 2017 | www.quora.com
Joe Zbiciak , Employed Updated Nov 5 2017 · Author has 2k answers and 7.3m answer views
Joachim Pense , Perl is my language of choice Answered Nov 4, 2017 · Author has 6.1k answers and 7.1m answer viewsPerl bashing is popular sport among a particularly vocal crowd.
Perl is extremely flexible. Perl holds up TIMTOWTDI ( There Is More Than One Way To Do It ) as a virtue. Larry Wall's Twitter handle is @TimToady, for goodness sake!
That flexibility makes it extremely powerful. It also makes it extremely easy to write code that nobody else can understand. (Hence, Tim Toady Bicarbonate.)
You can pack a lot of punch in a one-liner in Perl:
- print $fo map { sprintf ( " .pword 0x%.6X\n" , $_ ) } unpack ( "n*" , $data );
That one-liner takes a block of raw data (in
$data
), expands it to an array of values, and th...It is still used, but its usage is declining. People use Python today in situations when they would have used Perl ten years ago.
The problem is that Perl is extremely pragmatic. It is designed to be “a language to get your job done”, and it does that well; however, that led to rejection by language formalists. However, Perl is very well designed, only it is well designed for professionals who grab in the dark expecting that at this place there should be a button to do the desired functionality, and indeed, there will be the button. It is much safer to use than for example C (the sharp knife that was delivered without a handle), but it is easy to produce quite messy code with it if you are a newbie who doesn’t understand/feel the principles of Perl. In the 90s and 2000s, it was the goto web language, so the web was full of terrible programs written by those newbies, and that led to the bad reputation.
Strangely enough, PHP, which is frowned upon a lot by Perl programmers, won the favour of the noobs, but never got the general bad reputation; in fact it is missing the design principles I mentioned, that language is just a product of adhockery.
But today, Perl went back to its status as a niche language, and you cannot mention it in presence of a lady, so to speak. Its support is slowly waning; I’d suggest to learn Python, but don’t force me to learn it as well.
John Robinson , Software Engineer Answered Nov 4, 2017 · Author has 416 answers and 92.9k answer views
Gary Puckering , Fluent in C#, Python, and perl; rusty in C/C++ and too many others to count Answered Apr 25, 2018 · Author has 1.1k answers and 2.5m answer viewsYou should learn things that make your life easier or better. I am not an excellent Perl user, but it is usually my go-to scripting language for important projects. The syntax is difficult, and it's very easy to forget how to use it when you take significant time away from it.
That being said, I love how regular expressions work in Perl. I can use sed like commands $myvar =~ s/old/new/g for string replacement when processing or filtering strings. It's much nicer than other languages imo.
I also like Perls foreach loops and its data structures.
I tried writing a program of moderate length in Python and it just seemed to be taking up too much space. I stopped part way though and switched to Perl. I got the whole thing completed in much less space (lines), and seemed to have an easier time doing it.
I am not a super fanboy, but it has just always worked for me in the past, and I can't outright discount it because of that.
Also, look up CPAN modules. The installation of those for me on GNU is a breeze.
My last scripting project I did in Python and it went very well. I will probably shift to Python more in the future, because I would like to build a stronger basis of knowledge with the modules and basics of Python so that I can hop into it and create some powerful stuff when needed. Ie I want to focus on 1–3 languages, and learn them to a higher level instead of being "just ok" with 5–7.
Why is Perl so hated and not commonly used?
I think there are several reasons why Perl has a lot of detractors
- Sigils . A lot of programmers seem to hate the $@% sigils! If you are coming from a strongly typed language like C/C++, and also hate things like Hungarian notation, you won’t like sigils.
- One liners. As others have commented, writing dense and even obfuscated code rose to the level of sport within the Perl community. The same thing happened, years earlier, in the APL community. Programmers and managers saw that you could write unmaintainable code, and that helped instill a fear that it was unavoidable and that perhaps the language was flawed because it didn’t discourage the practice.
- Auto-magic . The programming language PL/I, which attempted to combine the best of COBOL and FORTRAN, went absolutely crazy with default behaviors. I remember reading an article in the 1970’s where programming in PL/I was described as being like flying a Boeing 747. The cockpit is filled with hundreds of buttons, knobs, switches and levers. The autopilot does most of the work, but trying to figure out the interaction between it and things you manually set can be bewildering. Perl, to some extent, suffers from the same problem. In Perl 5, without enabling warnings and strict, variables spring into life simply by naming them. A typo can instantiate and entirely new variable. Hashes get new keys simply by an attempt to access a key. You can increment a scalar that contains a string and it’ll try to generate a sequence using the string as a pattern (e.g. a, b, c … z, aa, ab …). If you come from a language where you control everything, all this auto-magic stuff can really bite you in the ass.
- An odd object-oriented syntax. Until Moose (and now Moo and Mouse) came along, writing classes in Perl meant using keywords like package and bless, as well as rolling all your own accessor methods. If you come from C++, Java , Python or just about any other language supporting OO your first question is going to be: where’s the friggin’ class statement!
- Dynamic typing . Some people like it. Some hate it. There are modules that let you add typing I’d you wish, though it’ll only be enforced at run time.
- No subroutine signatures . Although Perl 5 now supports subroutine signatures, they are still considered “experimental”. This is a turn-off for most programmers who are used to them. Per Damien Conway’s recommendations, I always unpack all the arguments from @_in the first line of a subroutine, which ends up looking just like a subroutine signature. (I almost never use shift for this purpose.)
- Lots of magic symbols . Although you can use English names, and should do so for more maintainable code, many Perl programmers stick to using special names like $_, $’, $; etc. This makes Perl code look very cryptic, and increases your cognitive load when working with the language. It’s a lot to remember. But if you use the English names, you can largely avoid this issue.
- Perl 6 is a discontinuous evolution . Although Perl 5 continues to evolve, and some of the advances that have been put in Perl 6 have been added to Perl 5, the lack of,upward compatibility between 5 and 6 creates uncertainly about its future.
And why should I learn it?
Despite the above, you can write maintainable code in Perl by following Damian Comways’s Perl Best Practices. The utility perlcritic can be used to help train yourself to write better Perl code.
Perl is multi-paradigm. In execution, it’s faster than Python. It has a superb ecosystem in cpan , where you can find a module to help you solve almost every imaginable problem. For command line utilities, file system administration, database administration, data extraction-transformation-loading tasks, batch processes, connecting disparate systems, and quick and dirty scripts, it’s often the best tool for the job.
I frequently use Perl in connection with Excel. You can do a lot in Excel, and it provides a great interactive UI. But complex formulas can be a pain to get right, and it can be tedious to write code in VBA. Often, I find it much quicker to just copy cells to the clipboard, switch to a command shell, run a Perl script over the data, sending the results to the clipboard, switch back to Excel, and then paste the results in situ or in a new location.
Perl is also deep. It does a good job of supporting imperative programming, OOP, and functional programming. For more on the latter, see the book Higher-Order Perl .
Perl is powerful. Perl is fast. Perl is an effective tool to have in your toolkit. Those are all good reasons to learn it.
Reed White , former Engineer at Hewlett-Packard (1978-2000) Answered Nov 7, 2017 · Author has 2.3k answers and 380.8k answer views
Yes, Perl takes verbal abuse; but in truth, it is an extremely powerful, reliable language. In my opinion, one of its outstanding characteristics is that you don't need much knowledge before you can write useful programs. As time goes by, you gradually learn the real power of the language.
However, because Perl-bashing is popular, you might better put your efforts into learning Python, which is also quite capable.
Richard Conto , Programmer in multiple languages. Debugger in even more Answered Dec 18, 2017 · Author has 5.9k answers and 4.3m answer views
Perl bashing is largely hear-say. People hear something and they say it. It doesn't require a great deal of thought.
As for Perl not commonly being used - that's BS. It may not be as common as the usual gang of languages, but there's an enormous amount of work done in Perl.
As for you you should learn Perl, it's for the same reason you would learn any other language - it helps you solve a particular problem better than another language available. And yes, that can be a very subjective decision to make.
Randal L. Schwartz , Literally "wrote the books" on it Answered Mar 3, 2018 · Author has 108 answers and 90.5k answer views
The truth is, that by any metric, more Perl is being done today than during the dot com boom. It's just a somewhat smaller piece of a much bigger pie. In fact, I've heard from some hiring managers that there's actually a shortage of Perl programmers, and not just for maintaining projects, but for new greenfield deploys.
Nov 14, 2019 | stackoverflow.com
Asked 7 years, 7 months ago Active 7 years, 7 months ago Viewed 20k times 8 1
brian d foy ,Jul 17, 2014 at 17:54
How do I change the value of a variable in the package used by a module so that subroutines in that module can use it?Here's my test case:
testmodule.pm:
package testmodule; use strict; use warnings; require Exporter; our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); @ISA = qw(Exporter); @EXPORT = qw(testsub); my $greeting = "hello testmodule"; my $var2; sub testsub { printf "__PACKAGE__: %s\n", __PACKAGE__; printf "\$main::greeting: %s\n", $main::greeting; printf "\$greeting: %s\n", $greeting; printf "\$testmodule::greeting: %s\n", $testmodule::greeting; printf "\$var2: %s\n", $var2; } # End testsub 1;testscript.pl:
#!/usr/bin/perl -w use strict; use warnings; use testmodule; our $greeting = "hello main"; my $var2 = "my var2 in testscript"; $testmodule::greeting = "hello testmodule from testscript"; $testmodule::var2 = "hello var2 from testscript"; testsub();output:
Name "testmodule::var2" used only once: possible typo at ./testscript.pl line 11. __PACKAGE__: testmodule $main::greeting: hello main $greeting: hello testmodule $testmodule::greeting: hello testmodule from testscript Use of uninitialized value $var2 in printf at testmodule.pm line 20. $var2:I expected
$greeting
and$testmodule::greeting
to be the same since the package of the subroutine istestmodule
.I guess this has something to do with the way
use
d modules areeval
d as if in aBEGIN
block, but I'd like to understand it better.I was hoping to set the value of the variable from the main script and use it in the module's subroutine without using the fully-qualified name of the variable.
perl-user ,Sep 5, 2013 at 13:58
As you found out, when you usemy
, you are creating a locally scoped non-package variable. To create a package variable, you useour
and notmy
:my $foo = "this is a locally scoped, non-package variable"; our $bar = "This is a package variable that's visible in the entire package";Even better:
{ my $foo = "This variable is only available in this block"; our $bar = "This variable is available in the whole package": } print "$foo\n"; #Whoops! Undefined variable print "$bar\n"; #Bar is still defined even out of the blockWhen you don't put
use strict
in your program, all variables defined are package variables. That's why when you don't put it, it works the way you think it should and putting it in breaks your program.However, as you can see in the following example, using
Fileour
will solve your dilemma:Local/Foo.pm
#! /usr/local/bin perl package Local::Foo; use strict; use warnings; use feature qw(say); use Exporter 'import'; our @EXPORT = qw(testme); our $bar = "This is the package's bar value!"; sub testme { # $foo is a locally scoped, non-package variable. It's undefined and an error say qq(The value of \$main::foo is "$main::foo"); # $bar is defined in package main::, and will print out say qq(The value of \$main::bar is "$main::bar"); # These both refer to $Local::Foo::bar say qq(The value of \$Local::Foo::bar is "$Local::Foo::bar"); say qq(The value of bar is "$bar"); } 1;Filetest.pl
#! /usr/local/bin perl use strict; use warnings; use feature qw(say); use Local::Foo; my $foo = "This is foo"; our $bar = "This is bar"; testme; say ""; $Local::Foo::bar = "This is the NEW value for the package's bar"; testmeAnd, the output is:
Use of uninitialized value $foo in concatenation (.) or string at Local/Foo.pm line 14. The value of $main::foo is "" The value of $main::bar is "This is bar" The value of $Local::Foo::bar is "This is the package's bar value!" The value of bar is "This is the package's bar value!" Use of uninitialized value $foo in concatenation (.) or string at Local/Foo.pm line 14. The value of $main::foo is "" The value of $main::bar is "This is bar" The value of $Local::Foo::bar is "This is the NEW value for the package's bar" The value of bar is "This is the NEW value for the package's bar"The error message you're getting is the result of
$foo
being a local variable, and thus isn't visible inside the package. Meanwhile,$bar
is a package variable and is visible.Sometimes, it can be a bit tricky:
if ($bar -eq "one") { my $foo = 1; } else { my $foo = 2; } print "Foo = $foo\n";That doesn't work because
$foo
only bas a value inside theif
block. You have to do this:my $foo; if ($bar -eq "one") { $foo = 1; } else { $foo = 2; } print "Foo = $foo\n"; #This works!Yes, it can be a bit to get your head wrapped around it initially, but the use of
use strict;
anduse warnings;
is now de rigueur and for good reasons. The use ofuse strict;
anduse warnings;
probably has eliminated 90% of the mistakes people make in Perl. You can't make a mistake of setting the value of$foo
in one part of the program, and attempting to use$Foo
in another. It's one of the things I really miss in Python.> ,
After reading Variable Scoping in Perl: the basics more carefully, I realized that a variable declared withmy
isn't in the current package. For example, in a simple script with no modules if I declaremy $var = "hello"
$main::var
still doesn't have a value.The way that this applies in this case is in the module. Since
my $greeting
is declared in the file, that hides the package's version of$greeting
and that's the value which the subroutine sees. If I don't declare the variable first, the subroutine would see the package variable, but it doesn't get that far because Iuse strict
.If I don't
use strict
and don't declaremy $greeting
, it works as I would have expected. Another way to get the intended value and not breakuse strict
is to useour $greeting
. The difference being that my declares a variable in the current scope while our declares a variable in the current package .
Nov 13, 2019 | stackoverflow.com
Paul Tomblin ,Oct 19, 2010 at 13:38
I want to repeatedly search for values in an array that does not change.So far, I have been doing it this way: I put the values in a hash (so I have an array and a hash with essentially the same contents) and I search the hash using
exists
.I don't like having two different variables (the array and the hash) that both store the same thing; however, the hash is much faster for searching.
I found out that there is a
~~
(smartmatch) operator in Perl 5.10. How efficient is it when searching for a scalar in an array?> ,
If you want to search for a single scalar in an array, you can use List::Util 'sfirst
subroutine. It stops as soon as it knows the answer. I don't expect this to be faster than a hash lookup if you already have the hash , but when you consider creating the hash and having it in memory, it might be more convenient for you to just search the array you already have.As for the smarts of the smart-match operator, if you want to see how smart it is, test it. :)
There are at least three cases you want to examine. The worst case is that every element you want to find is at the end. The best case is that every element you want to find is at the beginning. The likely case is that the elements you want to find average out to being in the middle.
Now, before I start this benchmark, I expect that if the smart match can short circuit (and it can; its documented in perlsyn ), that the best case times will stay the same despite the array size, while the other ones get increasingly worse. If it can't short circuit and has to scan the entire array every time, there should be no difference in the times because every case involves the same amount of work.
Here's a benchmark:
#!perl use 5.12.2; use strict; use warnings; use Benchmark qw(cmpthese); my @hits = qw(A B C); my @base = qw(one two three four five six) x ( $ARGV[0] || 1 ); my @at_end = ( @base, @hits ); my @at_beginning = ( @hits, @base ); my @in_middle = @base; splice @in_middle, int( @in_middle / 2 ), 0, @hits; my @random = @base; foreach my $item ( @hits ) { my $index = int rand @random; splice @random, $index, 0, $item; } sub count { my( $hits, $candidates ) = @_; my $count; foreach ( @$hits ) { when( $candidates ) { $count++ } } $count; } cmpthese(-5, { hits_beginning => sub { my $count = count( \@hits, \@at_beginning ) }, hits_end => sub { my $count = count( \@hits, \@at_end ) }, hits_middle => sub { my $count = count( \@hits, \@in_middle ) }, hits_random => sub { my $count = count( \@hits, \@random ) }, control => sub { my $count = count( [], [] ) }, } );div class="answercell post-layout--right,
Here's how the various parts did. Note that this is a logarithmic plot on both axes, so the slopes of the plunging lines aren't as close as they look:So, it looks like the smart match operator is a bit smart, but that doesn't really help you because you still might have to scan the entire array. You probably don't know ahead of time where you'll find your elements. I expect a hash will perform the same as the best case smart match, even if you have to give up some memory for it.
Okay, so the smart match being smart times two is great, but the real question is "Should I use it?". The alternative is a hash lookup, and it's been bugging me that I haven't considered that case.
As with any benchmark, I start off thinking about what the results might be before I actually test them. I expect that if I already have the hash, looking up a value is going to be lightning fast. That case isn't a problem. I'm more interested in the case where I don't have the hash yet. How quickly can I make the hash and lookup a key? I expect that to perform not so well, but is it still better than the worst case smart match?
Before you see the benchmark, though, remember that there's almost never enough information about which technique you should use just by looking at the numbers. The context of the problem selects the best technique, not the fastest, contextless micro-benchmark. Consider a couple of cases that would select different techniques:
- You have one array you will search repeatedly
- You always get a new array that you only need to search once
- You get very large arrays but have limited memory
Now, keeping those in mind, I add to my previous program:
my %old_hash = map {$_,1} @in_middle; cmpthese(-5, { ..., new_hash => sub { my %h = map {$_,1} @in_middle; my $count = 0; foreach ( @hits ) { $count++ if exists $h{$_} } $count; }, old_hash => sub { my $count = 0; foreach ( @hits ) { $count++ if exists $old_hash{$_} } $count; }, control_hash => sub { my $count = 0; foreach ( @hits ) { $count++ } $count; }, } );Here's the plot. The colors are a bit difficult to distinguish. The lowest line there is the case where you have to create the hash any time you want to search it. That's pretty poor. The highest two (green) lines are the control for the hash (no hash actually there) and the existing hash lookup. This is a log/log plot; those two cases are faster than even the smart match control (which just calls a subroutine).
There are a few other things to note. The lines for the "random" case are a bit different. That's understandable because each benchmark (so, once per array scale run) randomly places the hit elements in the candidate array. Some runs put them a bit earlier and some a bit later, but since I only make the
@random
array once per run of the entire program, they move around a bit. That means that the bumps in the line aren't significant. If I tried all positions and averaged, I expect that "random" line to be the same as the "middle" line.Now, looking at these results, I'd say that a smart-match is much faster in its worst case than the hash lookup is in its worst case. That makes sense. To create a hash, I have to visit every element of the array and also make the hash, which is a lot of copying. There's no copying with the smart match.
Here's a further case I won't examine though. When does the hash become better than the smart match? That is, when does the overhead of creating the hash spread out enough over repeated searches that the hash is the better choice?
,
Fast for small numbers of potential matches, but not faster than the hash. Hashes are really the right tool for testing set membership. Since hash access is O(log n) and smartmatch on an array is still O(n) linear scan (albeit short-circuiting, unlike grep), with larger numbers of values in the allowed matches, smartmatch gets relatively worse. Benchmark code (matching against 3 values):#!perl use 5.12.0; use Benchmark qw(cmpthese); my @hits = qw(one two three); my @candidates = qw(one two three four five six); # 50% hit rate my %hash; @hash{@hits} = (); sub count_hits_hash { my $count = 0; for (@_) { $count++ if exists $hash{$_}; } $count; } sub count_hits_smartmatch { my $count = 0; for (@_) { $count++ when @hits; } $count; } say count_hits_hash(@candidates); say count_hits_smartmatch(@candidates); cmpthese(-5, { hash => sub { count_hits_hash((@candidates) x 1000) }, smartmatch => sub { count_hits_smartmatch((@candidates) x 1000) }, } );Benchmark results:Rate smartmatch hash smartmatch 404/s -- -65% hash 1144/s 183% --
Nov 13, 2019 | stackoverflow.com
Static code analysis module in Perl Ask Question Asked 7 years, 5 months ago Active 1 year, 7 months ago Viewed 835 times 0
DavidO ,Jun 12, 2012 at 9:13
Is there any static code analysis module in Perl except B::Lint and Perl::Critic? How effective is Module::Checkstyle?> ,
There is a post on perlmonks.org asking if PPI can be used for static analysis. PPI is the power behind Perl::Critic, according to the reviews of this module. (I have not used it yet).Then there is perltidy .
Nov 12, 2019 | metacpan.org
Module::Checkstyle is a tool similar to checkstyle http://checkstyle.sourceforge.net for Java. It allows you to validate that your code confirms to a set of guidelines checking various things such as indentation, naming, whitespace, complexity and so forth.
Module::Checkstyle is also extensible so your organization can implement custom checks that are not provided by the standard distribution. There is a guide on how to write checks in Module::Checkstyle::Check
Module::Checkstyle is mostly used via the provided
module-checkstyle
tool. You probablly want to read module-checkstyle .NAMEmodule-checkstyle - Check that your code keeps style
SYNOPSISmodule-checkstyle [options] [file and directories ...]
This program is the command-line interface to Module::Checkstyle .
You invoke it by supplying a list of files or directories that contain Perl code that should be checked aginst the configuration. Any problems found will be reported on standard out.
OPTIONS
- -help
- Print a brief help message and exits.
- -man
- Prints the manual page and exists.
- -config
- Use an alternate config file instead of ~/.module-checkstyle/config .
- -all
- Don't ignore common files when traversing directories. Common files are things such as blib/* t/* Makefile.PL etc.
- -debug
- Turn on debugging information.
- -version
- Display version information.
Nov 12, 2019 | stackoverflow.com
Static code analysis module in Perl Ask Question Asked 7 years, 5 months ago Active 1 year, 7 months ago Viewed 835 times 0
DavidO ,Jun 12, 2012 at 9:13
Is there any static code analysis module in Perl except B::Lint and Perl::Critic? How effective is Module::Checkstyle?> ,
There is a post on perlmonks.org asking if PPI can be used for static analysis. PPI is the power behind Perl::Critic, according to the reviews of this module. (I have not used it yet).Then there is perltidy .
Nov 12, 2019 | metacpan.org
Module::Checkstyle is a tool similar to checkstyle http://checkstyle.sourceforge.net for Java. It allows you to validate that your code confirms to a set of guidelines checking various things such as indentation, naming, whitespace, complexity and so forth.
Module::Checkstyle is also extensible so your organization can implement custom checks that are not provided by the standard distribution. There is a guide on how to write checks in Module::Checkstyle::Check
Module::Checkstyle is mostly used via the provided
module-checkstyle
tool. You probablly want to read module-checkstyle .NAMEmodule-checkstyle - Check that your code keeps style
SYNOPSISmodule-checkstyle [options] [file and directories ...]
This program is the command-line interface to Module::Checkstyle .
You invoke it by supplying a list of files or directories that contain Perl code that should be checked aginst the configuration. Any problems found will be reported on standard out.
OPTIONS
- -help
- Print a brief help message and exits.
- -man
- Prints the manual page and exists.
- -config
- Use an alternate config file instead of ~/.module-checkstyle/config .
- -all
- Don't ignore common files when traversing directories. Common files are things such as blib/* t/* Makefile.PL etc.
- -debug
- Turn on debugging information.
- -version
- Display version information.
Nov 11, 2019 | stackoverflow.com
- Home
- Public
- Stack Overflow
- Tags
- Users
- Jobs
- Teams What's this?
Teams
Q&A for Work
Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information.
Learn more- First 10 Free
- How fast is Perl's smartmatch operator when searching for a scalar in an array? Ask Question Asked 8 years, 11 months ago Active 3 years ago Viewed 5k times 18 6
Paul Tomblin ,Oct 19, 2010 at 13:38
I want to repeatedly search for values in an array that does not change.So far, I have been doing it this way: I put the values in a hash (so I have an array and a hash with essentially the same contents) and I search the hash using
exists
.I don't like having two different variables (the array and the hash) that both store the same thing; however, the hash is much faster for searching.
I found out that there is a
~~
(smartmatch) operator in Perl 5.10. How efficient is it when searching for a scalar in an array?> ,
If you want to search for a single scalar in an array, you can use List::Util 'sfirst
subroutine. It stops as soon as it knows the answer. I don't expect this to be faster than a hash lookup if you already have the hash , but when you consider creating the hash and having it in memory, it might be more convenient for you to just search the array you already have.As for the smarts of the smart-match operator, if you want to see how smart it is, test it. :)
There are at least three cases you want to examine. The worst case is that every element you want to find is at the end. The best case is that every element you want to find is at the beginning. The likely case is that the elements you want to find average out to being in the middle.
Now, before I start this benchmark, I expect that if the smart match can short circuit (and it can; its documented in perlsyn ), that the best case times will stay the same despite the array size, while the other ones get increasingly worse. If it can't short circuit and has to scan the entire array every time, there should be no difference in the times because every case involves the same amount of work.
Here's a benchmark:
#!perl use 5.12.2; use strict; use warnings; use Benchmark qw(cmpthese); my @hits = qw(A B C); my @base = qw(one two three four five six) x ( $ARGV[0] || 1 ); my @at_end = ( @base, @hits ); my @at_beginning = ( @hits, @base ); my @in_middle = @base; splice @in_middle, int( @in_middle / 2 ), 0, @hits; my @random = @base; foreach my $item ( @hits ) { my $index = int rand @random; splice @random, $index, 0, $item; } sub count { my( $hits, $candidates ) = @_; my $count; foreach ( @$hits ) { when( $candidates ) { $count++ } } $count; } cmpthese(-5, { hits_beginning => sub { my $count = count( \@hits, \@at_beginning ) }, hits_end => sub { my $count = count( \@hits, \@at_end ) }, hits_middle => sub { my $count = count( \@hits, \@in_middle ) }, hits_random => sub { my $count = count( \@hits, \@random ) }, control => sub { my $count = count( [], [] ) }, } );div class="answercell post-layout--right,
Here's how the various parts did. Note that this is a logarithmic plot on both axes, so the slopes of the plunging lines aren't as close as they look:So, it looks like the smart match operator is a bit smart, but that doesn't really help you because you still might have to scan the entire array. You probably don't know ahead of time where you'll find your elements. I expect a hash will perform the same as the best case smart match, even if you have to give up some memory for it.
Okay, so the smart match being smart times two is great, but the real question is "Should I use it?". The alternative is a hash lookup, and it's been bugging me that I haven't considered that case.
As with any benchmark, I start off thinking about what the results might be before I actually test them. I expect that if I already have the hash, looking up a value is going to be lightning fast. That case isn't a problem. I'm more interested in the case where I don't have the hash yet. How quickly can I make the hash and lookup a key? I expect that to perform not so well, but is it still better than the worst case smart match?
Before you see the benchmark, though, remember that there's almost never enough information about which technique you should use just by looking at the numbers. The context of the problem selects the best technique, not the fastest, contextless micro-benchmark. Consider a couple of cases that would select different techniques:
- You have one array you will search repeatedly
- You always get a new array that you only need to search once
- You get very large arrays but have limited memory
Now, keeping those in mind, I add to my previous program:
my %old_hash = map {$_,1} @in_middle; cmpthese(-5, { ..., new_hash => sub { my %h = map {$_,1} @in_middle; my $count = 0; foreach ( @hits ) { $count++ if exists $h{$_} } $count; }, old_hash => sub { my $count = 0; foreach ( @hits ) { $count++ if exists $old_hash{$_} } $count; }, control_hash => sub { my $count = 0; foreach ( @hits ) { $count++ } $count; }, } );Here's the plot. The colors are a bit difficult to distinguish. The lowest line there is the case where you have to create the hash any time you want to search it. That's pretty poor. The highest two (green) lines are the control for the hash (no hash actually there) and the existing hash lookup. This is a log/log plot; those two cases are faster than even the smart match control (which just calls a subroutine).
There are a few other things to note. The lines for the "random" case are a bit different. That's understandable because each benchmark (so, once per array scale run) randomly places the hit elements in the candidate array. Some runs put them a bit earlier and some a bit later, but since I only make the
@random
array once per run of the entire program, they move around a bit. That means that the bumps in the line aren't significant. If I tried all positions and averaged, I expect that "random" line to be the same as the "middle" line.Now, looking at these results, I'd say that a smart-match is much faster in its worst case than the hash lookup is in its worst case. That makes sense. To create a hash, I have to visit every element of the array and also make the hash, which is a lot of copying. There's no copying with the smart match.
Here's a further case I won't examine though. When does the hash become better than the smart match? That is, when does the overhead of creating the hash spread out enough over repeated searches that the hash is the better choice?
,
Fast for small numbers of potential matches, but not faster than the hash. Hashes are really the right tool for testing set membership. Since hash access is O(log n) and smartmatch on an array is still O(n) linear scan (albeit short-circuiting, unlike grep), with larger numbers of values in the allowed matches, smartmatch gets relatively worse. Benchmark code (matching against 3 values):#!perl use 5.12.0; use Benchmark qw(cmpthese); my @hits = qw(one two three); my @candidates = qw(one two three four five six); # 50% hit rate my %hash; @hash{@hits} = (); sub count_hits_hash { my $count = 0; for (@_) { $count++ if exists $hash{$_}; } $count; } sub count_hits_smartmatch { my $count = 0; for (@_) { $count++ when @hits; } $count; } say count_hits_hash(@candidates); say count_hits_smartmatch(@candidates); cmpthese(-5, { hash => sub { count_hits_hash((@candidates) x 1000) }, smartmatch => sub { count_hits_smartmatch((@candidates) x 1000) }, } );Benchmark results:Rate smartmatch hash smartmatch 404/s -- -65% hash 1144/s 183% --
Nov 11, 2019 | www.quora.com
Christoph Neumann Answered Jun 6 2015
For web workflows check out QuantifiedCode . It's a data-driven code quality platform we've built to automate code reviews. It offers you static analysis as a service--for free.
Other tools out there are Pylint , PyFlakes , PyChecker , PEP8 , Frosted (a fork of PyFlakes) and Flake8 (a wrapper around PyFlakes and PEP8).
For more details, I compiled a tables that compares the most popular Python code analysis tools . 7.3k views · View 3 Upvoters Related Questions More Answers Below
Guillaume Bog , Python supertanker maintenance Answered Jul 9, 2012 Originally Answered: What is the best static analysis tool for Python?
- What are some static code analysis tools for Python, specifically to identify insecure coding practices?
- What are static analysis tools, and which are the best tools?
- What is the best IDE for Python?
- As a data scientist, do you use more R or Python or is it about the same?
- What are some pros and cons of using Python for data science?
I use pyflakes for code checking inside Vim and find it very useful. But still, pylint is better for pre-commit code checking. You should have two levels of code checking: errors that cannot be commited and warnings that are code-smells but can be commited. You can configure that and many other things with pylint.
Sometime you might think pylint is too picky: it may complain for something that you think is perfectly ok. Think twice about it. Very often, I found that the warning I found overly conservative some month ago was actually a very good advice.
So my answer is that pylint is reliable and robust, and I am not aware of a much better code analyzer.
pylint is very good for respecting PEP8
you can have pyflakes directly embedded in vim with this plugin:
http://www.vim.org/scripts/scrip...Alexa Alice Answered Jul 24, 2019 · Author has 278 answers and 53.4k answer views
Spending time in the static analysis will really(really) advantage you and your group as far as time spending on discovering bugs, as far as disclosing the code to extend newcomers, regarding undertaking costs and so on. On the off chance that you invest the energy doing it forthrightly, it might appear as though you're not chipping away at highlights but rather it will return to you later on you will profit by this sooner or later.
There are a couple of interesting points on our voyage for brilliant code. In the first place, this adventure isn't one of unadulterated objectivity. There are some solid sentiments of what top-notch code resembles.
While everybody can ideally concede to the identifiers referenced over, the manner in which they get accomplished is an emotional street. The most obstinate themes generally come up when you talk about accomplishing intelligibility, upkeep, and extensibility.
To know more details: Static Analysis 342 views Related Questions More Answers Below
- As a data scientist, do you use more R or Python or is it about the same?
- What are some pros and cons of using Python for data science?
- What are the tools available for R programming?
- What are some best tools to do static analysis of code in PHP?
- How do I learn static program analysis?
Dave Wade-Stein , Senior Instructor at DevelopIntelligence (2015-present) Answered Apr 15, 2018 · Author has 995 answers and 2.1m answer views
And if you're using Python 3.6+, you can add typing hints to your code and run mypy , a static typechecker over your code. (Technically, mypy will work with Python 2 code as well, but given that typing hints weren't added to Python until 3.5, you have to put the typing hints in comments which is a bit cumbersome and hard to maintain.)
Nov 11, 2019 | www.quora.com
What are the best tools for Python static analysis?
Christoph Neumann Answered Jun 6 2015
For web workflows check out QuantifiedCode . It's a data-driven code quality platform we've built to automate code reviews. It offers you static analysis as a service--for free.
Other tools out there are Pylint , PyFlakes , PyChecker , PEP8 , Frosted (a fork of PyFlakes) and Flake8 (a wrapper around PyFlakes and PEP8).
For more details, I compiled a tables that compares the most popular Python code analysis tools . 7.3k views · View 3 Upvoters Related Questions More Answers Below
Guillaume Bog , Python supertanker maintenance Answered Jul 9, 2012 Originally Answered: What is the best static analysis tool for Python?
- What are some static code analysis tools for Python, specifically to identify insecure coding practices?
- What are static analysis tools, and which are the best tools?
- What is the best IDE for Python?
- As a data scientist, do you use more R or Python or is it about the same?
- What are some pros and cons of using Python for data science?
I use pyflakes for code checking inside Vim and find it very useful. But still, pylint is better for pre-commit code checking. You should have two levels of code checking: errors that cannot be commited and warnings that are code-smells but can be commited. You can configure that and many other things with pylint.
Sometime you might think pylint is too picky: it may complain for something that you think is perfectly ok. Think twice about it. Very often, I found that the warning I found overly conservative some month ago was actually a very good advice.
So my answer is that pylint is reliable and robust, and I am not aware of a much better code analyzer.
pylint is very good for respecting PEP8
you can have pyflakes directly embedded in vim with this plugin:
http://www.vim.org/scripts/scrip...Alexa Alice Answered Jul 24, 2019 · Author has 278 answers and 53.4k answer views
Spending time in the static analysis will really(really) advantage you and your group as far as time spending on discovering bugs, as far as disclosing the code to extend newcomers, regarding undertaking costs and so on. On the off chance that you invest the energy doing it forthrightly, it might appear as though you're not chipping away at highlights but rather it will return to you later on you will profit by this sooner or later.
There are a couple of interesting points on our voyage for brilliant code. In the first place, this adventure isn't one of unadulterated objectivity. There are some solid sentiments of what top-notch code resembles.
While everybody can ideally concede to the identifiers referenced over, the manner in which they get accomplished is an emotional street. The most obstinate themes generally come up when you talk about accomplishing intelligibility, upkeep, and extensibility.
To know more details: Static Analysis 342 views Related Questions More Answers Below
- As a data scientist, do you use more R or Python or is it about the same?
- What are some pros and cons of using Python for data science?
- What are the tools available for R programming?
- What are some best tools to do static analysis of code in PHP?
- How do I learn static program analysis?
Dave Wade-Stein , Senior Instructor at DevelopIntelligence (2015-present) Answered Apr 15, 2018 · Author has 995 answers and 2.1m answer views
And if you're using Python 3.6+, you can add typing hints to your code and run mypy , a static typechecker over your code. (Technically, mypy will work with Python 2 code as well, but given that typing hints weren't added to Python until 3.5, you have to put the typing hints in comments which is a bit cumbersome and hard to maintain.)
Nov 10, 2019 | news.ycombinator.com
makecheck on Oct 7, 2015 [-]
In multiple organizations I have primarily seen Perl used in a very large, complex and established code bases that also make significant use of things like reading/writing Perl data structures.
Jul 27, 2016 | opensource.com
Did you know that Perl is a great programming language for system administrators? Perl is platform-independent so you can do things on different operating systems without rewriting your scripts. Scripting in Perl is quick and easy, and its portability makes your scripts amazingly useful. Here are a few examples, just to get your creative juices flowing! Renaming a bunch of files
Suppose you need to rename a whole bunch of files in a directory. In this case, we've got a directory full of
#!/usr/bin/perl.xml
files, and we want to rename them all to.html
. Easy-peasy!
use strict ;
use warnings ;foreach my $file ( glob "*.xml" ) {
my $new = substr ( $file , 0 , - 3 ) . "html" ;
rename $file , $new ;
}Then just cd to the directory where you need to make the change, and run the script. You could put this in a cron job, if you needed to run it regularly, and it is easily enhanced to accept parameters.
Speaking of accepting parameters, let's take a look at a script that does just that.
Creating a Linux user accountProgramming and development
- Programming cheat sheets
- New Python content
- Our latest JavaScript articles
- Recent Perl posts
- Red Hat Developers Blog
Suppose you need to regularly create Linux user accounts on your system, and the format of the username is first initial/last name, as is common in many businesses. (This is, of course, a good idea, until you get John Smith and Jane Smith working at the same company -- or want John to have two accounts, as he works part-time in two different departments. But humor me, okay?) Each user account needs to be in a group based on their department, and home directories are of the format /home/<department>/<username> . Let's take a look at a script to do that:
#!/usr/bin/env perl
use strict ;
use warnings ;my $adduser = '/usr/sbin/adduser' ;
use Getopt :: Long qw ( GetOptions ) ;
# If the user calls the script with no parameters,
# give them help!if ( not @ ARGV ) {
usage () ;
}# Gather our options; if they specify any undefined option,
# they'll get sent some help!my %opts ;
GetOptions ( \%opts ,
'fname=s' ,
'lname=s' ,
'dept=s' ,
'run' ,
) or usage () ;# Let's validate our inputs. All three parameters are
# required, and must be alphabetic.
# You could be clever, and do this with a foreach loop,
# but let's keep it simple for now.if ( not $opts { fname } or $opts { fname } !~ /^[a-zA-Z]+$/ ) {
usage ( "First name must be alphabetic" ) ;
}
if ( not $opts { lname } or $opts { lname } !~ /^[a-zA-Z]+$/ ) {
usage ( "Last name must be alphabetic" ) ;
}
if ( not $opts { dept } or $opts { dept } !~ /^[a-zA-Z]+$/ ) {
usage ( "Department must be alphabetic" ) ;
}# Construct the username and home directory
my $username = lc ( substr ( $opts { fname } , 0 , 1 ) . $opts { lname }) ;
my $home = "/home/$opts{dept}/$username" ;# Show them what we've got ready to go.
print "Name: $opts{fname} $opts{lname} \n " ;
print "Username: $username \n " ;
print "Department: $opts{dept} \n " ;
print "Home directory: $home \n\n " ;# use qq() here, so that the quotes in the --gecos flag
# get carried into the command!my $cmd = qq ( $adduser -- home $home -- ingroup $opts { dept } \\
-- gecos "$opts{fname} $opts{lname}" $username ) ;print "$cmd \n " ;
if ( $opts { run }) {
system $cmd ;
} else {
print "You need to add the --run flag to actually execute \n " ;
}sub usage {
my ( $msg ) = @_ ;
if ( $msg ) {
print "$msg \n\n " ;
}
print "Usage: $0 --fname FirstName --lname LastName --dept Department --run \n " ;
exit ;
}As with the previous script, there are opportunities for enhancement, but something like this might be all that you need for this task.
One more, just for fun!
Change copyright text in every Perl source file in a directory treeNow we're going to try a mass edit. Suppose you've got a directory full of code, and each file has a copyright statement somewhere in it. (Rich Bowen wrote a great article, Copyright statements proliferate inside open source code a couple of years ago that discusses the wisdom of copyright statements in open source code. It is a good read, and I recommend it highly. But again, humor me.) You want to change that text in each and every file in the directory tree.
#!/usr/bin/perlFile::Find
andFile::Slurp
are your friends!
use strict ;
use warnings ;use File :: Find qw ( find ) ;
use File :: Slurp qw ( read_file write_file ) ;# If the user gives a directory name, use that. Otherwise,
# use the current directory.my $dir = $ARGV [ 0 ] || '.' ;
# File::Find::find is kind of dark-arts magic.
# You give it a reference to some code,
# and a directory to hunt in, and it will
# execute that code on every file in the
# directory, and all subdirectories. In this
# case, \&change_file is the reference
# to our code, a subroutine. You could, if
# what you wanted to do was really short,
# include it in a { } block instead. But doing
# it this way is nice and readable.find ( \&change_file , $dir ) ;
sub change_file {
my $name = $_ ;# If the file is a directory, symlink, or other
# non-regular file, don't do anythingif ( not - f $name ) {
return ;
}
# If it's not Perl, don't do anything.if ( substr ( $name , - 3 ) ne ".pl" ) {
return ;
}
print "$name \n " ;# Gobble up the file, complete with carriage
# returns and everything.
# Be wary of this if you have very large files
# on a system with limited memory!my $data = read_file ( $name ) ;
# Use a regex to make the change. If the string appears
# more than once, this will change it everywhere!$data =~ s/Copyright Old/Copyright New/g ;
# Let's not ruin our original files
my $backup = "$name.bak" ;
rename $name , $backup ;
write_file ( $name , $data ) ;return ;
}Because of Perl's portability, you could use this script on a Windows system as well as a Linux system -- it Just Works because of the underlying Perl interpreter code. In our create-an-account code above, that one is not portable, but is Linux-specific because it uses Linux commands such as adduser .
In my experience, I've found it useful to have a Git repository of these things somewhere that I can clone on each new system I'm working with. Over time, you'll think of changes to make to the code to enhance the capabilities, or you'll add new scripts, and Git can help you make sure that all your tools and tricks are available on all your systems.
I hope these little scripts have given you some ideas how you can use Perl to make your system administration life a little easier. In addition to these longer scripts, take a look at a fantastic list of Perl one-liners, and links to other Perl magic assembled by Mischa Peterson.
Oct 22, 2019 | stackoverflow.com
Ask Question Asked 8 years, 5 months ago Active 8 years, 5 months ago Viewed 19k times 23 10
> ,May 2, 2011 at 18:58
Hey I've been using Linux for a while and thought it was time to finally dive into shell scripting.The problem is I've failed to find any significant advantage of using Bash over something like Perl or Python. Are there any performance or power differences between the two? I'd figure Python/Perl would be more well suited as far as power and efficiency goes.
Sebastian ,May 2, 2011 at 15:21
Two advantages come to mind:
- Simplicity: direct access to all wonderful linux tools
wc
,ls
,cat
,grep
,sed
... etc. Why constantly use python'ssubprocess
module?- I'm increasingly fond of using gnu parallel , with which you can execute your bash scripts in parallel. E.g. from the man page, batch create thumbs of all jpgs in directory in parallel:
ls *.jpg | parallel convert -geometry 120 {} thumb_{}
By the way, I usually have some python calls in my bash scripts (e.g. for plotting). Use whatever is best for the task!
Mario Peshev ,May 2, 2011 at 15:16
Perl scripts are usually (if not 100% of the times) faster than bash.A discussion on that: Perl vs Bash
reinierpost ,May 7, 2011 at 12:16
bash isn't a language so much as a command interpreter that's been hacked to death to allow for things that make it look like a scripting language. It's great for the simplest 1-5 line one-off tasks, but things that are dead simple in Perl or Python like array manipulation are horribly ugly in bash. I also find that bash tends not to pass two critical rules of thumb:
- The 6-month rule, which says you should be able to easily discern the purpose and basic mechanics of a script you wrote but haven't looked at in 6 months.
- The 'WTF per minute' rule. Everyone has their limit, and mine is pretty small. Once I get to 3 WTFs/min, I'm looking elsewhere.
As for 'shelling out' in scripting languages like Perl and Python, I find that I almost never need to do this, fwiw (disclaimer: I code almost 100% in Python). The Python os and shutil modules have most of what I need most of the time, and there are built-in modules for handling tarfiles, gzip files, zip files, etc. There's a glob module, an fnmatch module... there's a lot of stuff there. If you come across something you need to parallelize, then indent your code a level, put it in a 'run()' method, put that in a class that extends either threading.Thread or multiprocessing.Process, instantiate as many of those as you want, calling 'start()' on each one. Less than 5 minutes to get parallel execution generally.
Best of luck. Hope this helps.
daotoad ,May 2, 2011 at 17:40
For big projects use a language like Perl.There are a few things you can only do in bash (for example, alter the calling environment (when a script is sourced rather than run). Also, shell scripting is commonplace. It is worthwhile to learn the basics and learn your way around the available docs.
Plus there are times when knowing a shell well can save your bacon (on a fork-bombed system where you can't start any new processes, or if
/usr/bin
and or/usr/local/bin
fail to mount).Sebastian ,May 3, 2011 at 8:47
The advantage is that it's right there. Unless you use Python (or Perl) as your shell, writing a script to do a simple loop is a bunch of extra work.For short, simple scripts that call other programs, I'll use Bash. If I want to keep the output, odds are good that I'll trade up to Python.
For example:
for file in *; do process $file ; donewhere
process
is a program I want to run on each file, or...while true; do program_with_a_tendency_to_fail ; doneDoing either of those in Python or Perl is overkill.
For actually writing a program that I expect to maintain and use over time, Bash is rarely the right tool for the job. Particularly since most modern Unices come with both Perl and Python.
tchrist ,May 4, 2011 at 11:01
The most important advantage of POSIX shell scripts over Python or Perl scripts is that a POSIX shell is available on virtually every Unix machine. (There are also a few tasks shell scripts happen to be slightly more convenient for, but that's not a major issue.) If the portability is not an issue for you, I don't see much need to learn shell scripting.tchrist ,May 3, 2011 at 23:50
If you want to execute programs installed on the machine, nothing beats bash. You can always make a system call from Perl or Python, but I find it to be a hassle to read return values, etc.And since you know it will work pretty much anywhere throughout all of of time...
Alexandr Ciornii ,May 3, 2011 at 8:26
The advantage of shell scripting is that it's globally present on *ix boxes, and has a relatively stable core set of features you can rely on to run everywhere. With Perl and Python you have to worry about whether they're available and if so what version, as there have been significant syntactical incompatibilities throughout their lifespans. (Especially if you include Python 3 and Perl 6.)The disadvantage of shell scripting is everything else. Shell scripting languages are typically lacking in expressiveness, functionality and performance. And hacking command lines together from strings in a language without strong string processing features and libraries, to ensure the escaping is correct, invites security problems. Unless there's a compelling compatibility reason you need to go with shell, I would personally plump for a scripting language every time.
Oct 22, 2019 | developers.slashdot.org
(github.com) 100 hondo77 notes that Larry Wall has given his approval to the re-naming of Perl 6.
In the "Path to Raku" pull request, Larry Wall indicated his approval, leaving this comment: I am in favor of this change, because it reflects an ancient wisdom :
"No one sews a patch of unshrunk cloth on an old garment, for the patch will pull away from the garment, making the tear worse. Neither do people pour new wine into old wineskins. If they do, the skins will burst; the wine will run out and the wineskins will be ruined. No, they pour new wine into new wineskins, and both are preserved."
"Perl 6 will become Raku, assuming the four people who haven't yet approved the pull request give their okay," reports the Register, adding that Perl 5 will then become simply Perl .
Dozens of comments on that pull request have now already been marked as "outdated," and while a few contributors have made a point of abstaining from the approval process, reviewer Alex Daniel notes that "this pull request will be merged on October 14th if nobody in the list rejects it or requests more changes."
Nov 23, 2013 | stackoverflow.com
jholster ,Nov 23, 2013 at 21:20
I'm planning to learn Perl 5 and as I have only used PHP until now, I wanted to know a bit about how the languages differ from each other.As PHP started out as a set of "Perl hacks" it has obviously cloned some of Perls features.
- What are the main differences in the syntax? Is it true that with Perl you have more options and ways to express something?
- Why is Perl not used for dynamic websites very often anymore? What made PHP gain more popularity?
hobbs ,Jan 17, 2013 at 8:36
Perl and PHP are more different than alike. Let's consider Perl 5, since Perl 6 is still under development. Some differences, grouped roughly by subject:
- Perl has native regular expression support, including regexp literals. PHP uses Perl's regexp functions as an extension.
- Perl has quite a few more operators , including matching (
=~
,!~
), quote-like (qw
,qx
&c.), exponentiation (**
), string repetition (x
) and range (..
and...
). PHP has a few operators Perl doesn't, such as the error suppression operator (@
),instanceof
(though Perl does have theUniversal ::isa
method) andclone
.- In PHP,
new
is an operator. In Perl, it's the conventional name of an object creation subroutine defined in packages, nothing special as far as the language is concerned.- Perl logical operators return their arguments, while they return booleans in PHP. Try:
$foo = '' || 'bar';in each language. In Perl, you can even do
$foo ||= 'default'
to set $foo to a value if it's not already set. The shortest way of doing this in PHP is$foo = isset($foo) ? $foo : 'default';
(Update, in PHP 7.0+ you can do$foo = $foo ?? 'default'
)- Perl variable names indicate built-in type, of which Perl has three, and the type specifier is part of the name (called a " sigil "), so
$foo
is a different variable than@foo
or%foo
. (related to the previous point) Perl has separate symbol table entries for scalars, arrays, hashes, code, file/directory handles and formats. Each has its own namespace.- Perl gives access to the symbol table , though manipulating it isn't for the faint of heart. In PHP, symbol table manipulation is limited to creating references and the
extract
function.- Note that "references" has a different meaning in PHP and Perl. In PHP, references are symbol table aliases. In Perl, references are smart pointers.
- Perl has different types for integer-indexed collections (arrays) and string indexed collections (hashes). In PHP, they're the same type: an associative array/ordered map .
- Perl arrays aren't sparse: setting an element with index larger than the current size of the array will set all intervening elements to
undefined
(see perldata ). PHP arrays are sparse; setting an element won't set intervening elements.- Perl supports hash and array slices natively, and slices are assignable, which has all sorts of uses . In PHP, you use
array_slice
to extract a slice andarray_splice
to assign to a slice.- You can leave out the argument to the subscript operator in PHP for a bit of magic. In Perl, you can't leave out the subscript.
- Perl hashes are unordered .
- Perl has a large number of predefined and magic variables . PHP's predefined variables have quite a different purpose.
- Perl has statement modifiers : some control statements can be placed at the end of a statement.
- Perl supports dynamic scoping via the
local
keyword.- In addition, Perl has global, lexical (block), and package scope . PHP has global, function, object, class and namespace scope .
- In Perl, variables are global by default. In PHP, variables in functions are local by default.
- Perl supports explicit tail calls via the
goto
function.- Perl's prototypes provide more limited type checking for function arguments than PHP's type hinting . As a result, prototypes are of more limited utility than type hinting.
- In Perl, the last evaluated statement is returned as the value of a subroutine if the statement is an expression (i.e. it has a value), even if a return statement isn't used. If the last statement isn't an expression (i.e. doesn't have a value), such as a loop, the return value is unspecified (see perlsub ). In PHP, if there's no explicit return, the return value is NULL .
- Perl flattens lists (see perlsub ); for un-flattened data structures, use references.
@foo = qw(bar baz); @qux = ('qux', @foo, 'quux'); # @qux is an array containing 4 strings @bam = ('bug-AWWK!', \@foo, 'fum'); # @bam contains 3 elements: two strings and a array refPHP doesn't flatten arrays.
- Perl has special code blocks (
BEGIN
,UNITCHECK
,CHECK
,INIT
andEND
) that are executed. Unlike PHP'sauto_prepend_file
andauto_append_file
, there is no limit to the number of each type of code block. Also, the code blocks are defined within the scripts, whereas the PHP options are set in the server and per-directory config files.- In Perl, the semicolon separates statements . In PHP, it terminates them, excepting that a PHP close tag ("?>") can also terminate a statement.
- The value of expressions in Perl is context sensitive .
- Negative subscripts in Perl are relative to the end of the array.
$bam[-1]
is the final element of the array. Negative subscripts in PHP are subscripts like any other.- In Perl 5, classes are based on packages and look nothing like classes in PHP (or most other languages). Perl 6 classes are closer to PHP classes, but still quite different. (Perl 6 is different from Perl 5 in many other ways, but that's off topic.) Many of the differences between Perl 5 and PHP arise from the fact that most of the OO features are not built-in to Perl but based on hacks. For example,
$obj->method(@args)
gets translated to something like(ref $obj)::method($obj, @args)
. Non-exhaustive list:
- PHP automatically provides the special variable
$this
in methods. Perl passes a reference to the object as the first argument to methods.- Perl requires references to be blessed to create an object. Any reference can be blessed as an instance of a given class.
- In Perl, you can dynamically change inheritance via the packages
@ISA
variable.- Perl supports operator overloading .
- Strictly speaking, Perl doesn't have multiline comments, but the POD system can be used for the same affect.
- In Perl,
//
is an operator. In PHP, it's the start of a one-line comment.- Until PHP 5.3, PHP had terrible support for anonymous functions (the
create_function
function) and no support for closures.- PHP had nothing like Perl's packages until version 5.3, which introduced namespaces .
- Arguably, Perl's built-in support for exceptions looks almost nothing like exceptions in other languages, so much so that they scarcely seem like exceptions. You evaluate a block and check the value of
$@
(eval
instead oftry
,die
instead ofthrow
). TheErrorTry::Tiny module supports exceptions as you find them in other languages (as well as some other modules listed in Error's See Also section).PHP was inspired by Perl the same way Phantom of the Paradise was inspired by Phantom of the Opera , or Strange Brew was inspired by Hamlet . It's best to put the behavior specifics of PHP out of your mind when learning Perl, else you'll get tripped up.
My brain hurts now, so I'm going to stop.
Your Common Sense ,Mar 29, 2010 at 2:19
When PHP came to the scene, everyone were impressed with main differences from Perl:
- Input variables already in the global scope, no boring parsing.
- HTML embedding. Just
<?php ... ?>
anywhere. No boring templates.- On-screen error messages. No boring error log peeks.
- Easy to learn. No boring book reading.
As the time passed, everyone learned that they were not a benefit, hehe...
Quentin ,Jan 15, 2016 at 3:27
I've noticed that most PHP vs. Perl pages seem to be of thePHP is better than Perl because <insert lame reason here>
ilk, and rarely make reasonable comparisons.
Syntax-wise, you will find PHP is often easier to understand than Perl, particularly when you have little experience. For example, trimming a string of leading and trailing whitespace in PHP is simply
$string = trim($string);In Perl it is the somewhat more cryptic
$string =~ s/^\s+//; $string =~ s/\s+$//;(I believe this is slightly more efficient than a single line capture and replace, and also a little more understandable.) However, even though PHP is often more English-like, it sometimes still shows its roots as a wrapper for low level C, for example,
strpbrk
andstrspn
are probably rarely used, because most PHP dabblers write their own equivalent functions for anything too esoteric, rather than spending time exploring the manual. I also wonder about programmers for whom English is a second language, as everybody is on equal footing with things such as Perl, having to learn it from scratch.I have already mentioned the manual. PHP has a fine online manual, and unfortunately it needs it. I still refer to it from time to time for things that should be simple, such as order of parameters or function naming convention. With Perl, you will probably find you are referring to the manual a lot as you get started and then one day you will have an a-ha moment and never need it again. Well, at least not until you're more advanced and realize that not only is there more than one way, there is probably a better way, somebody else has probably already done it that better way, and perhaps you should just visit CPAN.
Perl does have a lot more options and ways to express things. This is not necessarily a good thing, although it allows code to be more readable if used wisely and at least one of the ways you are likely to be familiar with. There are certain styles and idioms that you will find yourself falling into, and I can heartily recommend reading Perl Best Practices (sooner rather than later), along with Perl Cookbook, Second Edition to get up to speed on solving common problems.
I believe the reason Perl is used less often in shared hosting environments is that historically the perceived slowness of CGI and hosts' unwillingness to install mod_perl due to security and configuration issues has made PHP a more attractive option. The cycle then continued, more people learned to use PHP because more hosts offered it, and more hosts offered it because that's what people wanted to use. The speed differences and security issues are rendered moot by FastCGI these days, and in most cases PHP is run out of FastCGI as well, rather than leaving it in the core of the web server.
Whether or not this is the case or there are other reasons, PHP became popular and a myriad of applications have been written in it. For the majority of people who just want an entry-level website with a simple blog or photo gallery, PHP is all they need so that's what the hosts promote. There should be nothing stopping you from using Perl (or anything else you choose) if you want.
At an enterprise level, I doubt you would find too much PHP in production (and please, no-one point at Facebook as a counter-example, I said enterprise level).
Leon Timmermans ,Mar 28, 2010 at 22:15
Perl is used plenty for websites, no less than Python and Ruby for example. That said, PHP is used way more often than any of those. I think the most important factors in that are PHP's ease of deployment and the ease to start with it.The differences in syntax are too many to sum up here, but generally it is true that it has more ways to express yourself (this is know as TIMTWOTDI, There Is More Than One Way To Do It).
Brad Gilbert ,Mar 29, 2010 at 4:04
My favorite thing about Perl is the way it handles arrays/lists. Here's an example of how you would make and use a Perl function (or "subroutine"), which makes use of this for arguments:sub multiply { my ($arg1, $arg2) = @_; # @_ is the array of arguments return $arg1 * $arg2; }In PHP you could do a similar thing with
list()
, but it's not quite the same; in Perl lists and arrays are actually treated the same (usually). You can also do things like:$week_day_name = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")[$week_day_index];And another difference that you MUST know about, is numerical/string comparison operators. In Perl, if you use
<
,>
,==
,!=
,<=>
, and so on, Perl converts both operands to numbers. If you want to convert as strings instead, you have to uselt
,gt
,eq
,ne
,cmp
(the respective equivalents of the operators listed previously). Examples where this will really get you:if ("a" == "b") { ... } # This is true. if ("a" == 0) { ... } # This is also true, for the same reason.Sorin Postelnicu, Aug 5, 2015 at 15:44
I do not need add anything to outis's fantastic answer, i want only show the answer for you question:Why is Perl not used for dynamic websites very often anymore? What made PHP gain more popularity than it?
Please check first some "Job Trends" sites - and you can make the judgement alone.
as you can see, perl is still a leader - but preferable for real applications not for toys. :)
Oct 13, 2019 | perlmaven.com
In response to an earlier article about undef one of the readers asked me:How do you eliminate a value in the middle of an array in Perl?
I am not sure if undef and eliminating values from an array are related, though I guess, if we see having a value of undef as being "empty", then I can understand the connection. In general though, setting something to be undef and deleting something is not the same.
Are you serious about Perl? Check out my Beginner Perl Maven book .
I have written it for you!Let's see first how we can set an element of an array to be undef and then how we can delete an element from an array.
We start with the following code:
- use Data :: Dumper qw ( Dumper );
- my @dwarfs = qw ( Doc Grumpy Happy Sleepy Sneezy Dopey Bashful );
- print Dumper \@dwarfs ;
When printed using Data::Dumper we get the following output:
$VAR1 = [ 'Doc', 'Grumpy', 'Happy', 'Sleepy', 'Sneezy', 'Dopey', 'Bashful' ];Set an element to undefUsing the return value of the undef() function:
- use Data :: Dumper qw ( Dumper );
- my @dwarfs = qw ( Doc Grumpy Happy Sleepy Sneezy Dopey Bashful );
- $dwarfs [ 3 ] = undef ;
- print Dumper \@dwarfs ;
This code will set element 3 (the 4th element of the array) to undef , but will NOT change the size of the array:
$VAR1 = [ 'Doc', 'Grumpy', 'Happy', undef, 'Sneezy', 'Dopey', 'Bashful' ];Using the undef() function directly on an element of an array yields similar results:
- use Data :: Dumper qw ( Dumper );
- my @dwarfs = qw ( Doc Grumpy Happy Sleepy Sneezy Dopey Bashful );
- undef $dwarfs [ 3 ];
- print Dumper \@dwarfs ;
So for our purposes $dwarfs[3] = undef; and undef $dwarfs[3]; do the same thing. They both can set a value to be undef .
Removing an element from the array using spliceThe splice function can totally eliminate the value from the array:
- use Data :: Dumper qw ( Dumper );
- my @dwarfs = qw ( Doc Grumpy Happy Sleepy Sneezy Dopey Bashful );
- splice @dwarfs,3,1;
- print Dumper \@dwarfs ;
$VAR1 = [ 'Doc', 'Grumpy', 'Happy', 'Sneezy', 'Dopey', 'Bashful' ];As you can see, in this case the array became one element shorter as we have removed one of the elements from the middle of the array.
This is how you can delete an element from an array .
Oct 13, 2019 | www.quora.com
Radu Grigore , argued rigor Answered Apr 22 2012 I think some of the main original contributions to Computer Science are the following:
He also did some work in mathematics. If I remember correctly, I saw him in a video saying that the article he is most proud of is The Birth of the Giant Component . Mark VandeWettering , I have a lab coat, trust me! Answered Jan 10, 2014 · Author has 7.2k answers and 23.3m answer views Knuth won the Turing Award in 1974 for his contributions to the analysis of algorithms I'd submit that his "expository" work in the form of The Art of Programming go well beyond simple exposition, and brought a rigor and precision to the analysis of algorithms which was (and probably still is) unparalleled in term of thoroughness and scope. There is more knowledge in the margins of The Art of Programming than there is in most programming courses. 1.2k views · View 7 Upvoters Eugene Miya , Ex-Journal Editor, parallelism DB, committees and conferences, etc. Answered Sep 9, 2014 · Author has 11.2k answers and 7.9m answer views Everyone cites and overcites TAOCP.
- Knuth-Bendix algorithm/orders, used in all modern theorem provers, such as Z3 and Vampire, which in turn are used by many program analysis tools. The article is Simple Word Problems in Universal Algebras .
- Knuth-Moris-Pratt string searching (already mentioned). The article is Fast Pattern Matching in Strings .
- LR(k) grammars, which lay the foundation for parser generators (think yacc and successors). The article is On the Translation of Languages from Left to Right .
- Attribute grammars, a way to define the semantics of a (simple) programming language that pops up in research every now and then. For example, they were used in the study of VLSI circuits. The article is Semantics of Context-Free Languages .
- I believe he was the first to profile programs. The article is An Empirical Study of FORTRAN Programs .
Start collecting Selected Papers (in|on) ... He has 8 volumes. If you need the titles consider Amazon: Online Shopping for Electronics, Apparel, Computers, Books, DVDs & more or Barnes &Noble: Books, Textbooks, eBooks, Toys, Games & More for their ToC.
Oct 13, 2019 | perlmaven.com
-e execute code on the command line
For one-off tasks it can be very useful to be able to run a piece of Perl code without creating a file. The code itself needs to be between quotes. Due to differences between the Unix/Linux shell and the MS Windows Command prompt we need to use different quotes around our code.
On Unix/Linux systsem (including Mac OSX) it is recommended to put our code in single quotes as in the following example:
$ perl -e 'print qq{Hello World\n}' Hello WorldOn MS Windows we must use double quotes around our code.
$ perl -e "print qq{Hello World\n}" Hello WorldInternally, it is probably the best to use q and qq instead of single-quote and double-quote, respectively. That might help reduce the confusion caused by the behavior of the shell and command prompt.
-E execute code on the command line with all the latest features enabledSince version 5.10 of Perl has been released, Perl includes some additional keywords (called features) in the language. For improved backward compatibility these keywords are only enabled if the user explicitly ask for them with use feature ... . For example by writing use feature qw(say); , or by declaring a minimal version of Perl with use 5.010; .
On the command line we can achieve the same by using -E instead of -e . It will turn on all the features of the version of Perl we are currently running.
For me the most important of all these features, at least in one-liners is the say keyword introduced in perl 5.10 . It is just print with a trailing newline added. Nothing fancy, but makes the one-liners even shorter.
The above examples would look like these:
Unix/Linux:
$ perl -E 'say q{Hello World}' Hello WorldMS Windows:
$ perl -E "say q{Hello World}" Hello WorldYou can notice the change from qq to q . As we don't need to include a newline \n in our strings we could switch from qq to q .
-n wrap the -e/-E code in a while loopIf we provide the -n command line option it will wrap our code provided using either the -e or the -E options in a while with a diamond operator .
So
perl -n -E 'say if /code/' file.txtis the same as
while (<>) { say if /code/; }That will go over all the lines of all the files provided on the command line (in this case it is file.txt) and print out every line that matches the /code/ regex.
-p is like -n with print $_The -p option is very similar to the -n flag, but it also prints the content of $_ at the end of each iteration.
So we could write:
perl -p -E 's/code/foobar/' file.txtwhich would become
while (<>) { s/code/foobar/ print; }That will print the result to the screen.
-i for in-place editingThe most common use of -p is together with the -i option that provides "in-place editing". It means that instead of printing to the screen, all the output generated by our one-liner will be written back to the same file it was taken from.
So this one-liner will replace the first appearance of the string "code" by "foobar" in every line of the file "file.txt".
perl -i -p -E 's/code/foobar/' file.txt
Oct 09, 2019 | perlmaven.com
Prev Next In most of the cases we either want a variable to be accessible only from inside a small scope, inside a function or even inside a loop. These variables get created when we enter the function (or the scope created by a a block) and destroyed when we leave the scope.In some cases, especially when we don't want to pay attention to our code, we want variables to be global, to be accessible from anywhere in our script and be destroyed only when the script ends. In General having such global variables is not a good practice.
In some cases we want a variable to stay alive between function calls, but still to be private to that function. We want it to retain its value between calls.
Are you serious about Perl? Check out my Beginner Perl Maven book .
I have written it for you!In the C programming language one can designate a variable to be a static variable . This means it gets initialized only once and it sticks around retaining its old value between function calls.
In Perl, the same can be achieved using the state variable which is available starting from version 5.10, but there is a construct that will work in every version of Perl 5. In a way it is even more powerful.
Let's create a counter as an example:
state variable
- use strict ;
- use warnings ;
- use 5.010 ;
- sub count {
- state $counter = 0 ;
- $counter ++;
- return $counter ;
- }
- say count ();
- say count ();
- say count ();
- #say $counter;
In this example, instead of using my to declare the internal variable , we used the state keyword.
$counter is initialized to 0 only once, the first time we call counter() . In subsequent calls, the line state $counter = 0; does not get executed and $counter has the same value as it had when we left the function the last time.Thus the output will be:
1 2 3If we removed the # from last line, it would generate a Global symbol "$counter" requires explicit package name at ... line ... error when trying to compile the script. This just shows that the variable $counter is not accessible outside the function.
state is executed in the first callCheck out this strange example:
- use strict ;
- use warnings ;
- use 5.010 ;
- sub count {
- state $counter = say "world" ;
- $counter ++;
- return $counter ;
- }
- say "hello" ;
- say count ();
- say count ();
- say count ();
This will print out
hello world 2 3 4showing that the state $counter = say "world"; line only gets executed once. In the first call to count() say , which was also added in version 5.10 , will return 1 upon success.
static variables in the "traditional" way
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my $counter = 0 ;
- sub count {
- $counter ++;
- return $counter ;
- }
- }
- say count ();
- say count ();
- say count ();
This provides the same result as the above version using state , except that this could work in older versions of perl as well. (Especially if I did not want to use the say keyword, that was also introduced in 5.10.)
This version works because functions declarations are global in perl - so count() is accessible in the main body of the script even though it was declared inside a block. On the other hand the variable $counter is not accessible from the outside world because it was declared inside the block. Lastly, but probably most importantly, it does not get destroyed when we leave the count() function (or when the execution is outside the block), because the existing count() function still references it.
Thus $count is effectively a static variable.
First assignment time
- use strict ;
- use warnings ;
- use 5.010 ;
- say "hi" ;
- {
- my $counter = say "world" ;
- sub count {
- $counter ++;
- return $counter ;
- }
- }
- say "hello" ;
- say count ();
- say count ();
- say count ();
hi world hello 2 3 4This shows that in this case too, the declaration and the initial assignment my $counter = say "world"; happens only once, but we can also see that the assignment happens before the first call to count() as if the my $counter = say "world"; statement was part of the control flow of the code outside of the block.
Shared static variableThis "traditional" or "home made" static variable has an extra feature. Because it does not belong to the the count() subroutine, but to the block surrounding it, we can declare more than one functions in that block and we can share this static variable between two or even more functions.
For example we could add a reset_counter() function:
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my $counter = 0 ;
- sub count {
- $counter ++;
- return $counter ;
- }
- sub reset_counter {
- $counter = 0 ;
- }
- }
- say count ();
- say count ();
- say count ();
- reset_counter ();
- say count ();
- say count ();
1 2 3 1 2Now both functions can access the $counter variable, but still nothing outside the enclosing block can access it.
Static arrays and hashesAs of now, you cannot use the state declaration in list context. This means you cannot write state @y = (1, 1); . This limitation could be overcome by some extra coding. For example in this implementation of the Fibonacci series, we checked if the array is empty and set the default values:
- use strict ;
- use warnings ;
- use 5.010 ;
- sub fib {
- state @y ;
- @y = ( 1 , 1 ) if not @y ; # workaround initialization
- push @y , $y [ 0 ]+ $y [ 1 ];
- return shift @y ;
- }
- say fib ();
- say fib ();
- say fib ();
- say fib ();
- say fib ();
Alternatively we could use the "old-style" static variable with the enclosing block.
Here is the example generating the Fibonacci series:
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my @y = ( 1 , 1 );
- sub fib {
- push @y , $y [ 0 ]+ $y [ 1 ];
- return shift @y ;
- }
- }
- say fib ();
- say fib ();
- say fib ();
- say fib ();
- say fib ();
Oct 09, 2019 | perlmaven.com
use vars
The problem is that use strict is complaining that there is a variable $x which is not declared with my and that it does not know about it. So we need a way to tell strict that it is ok. We know about the $x variable and we want to use it, but we want it to be a package variable. We don't want to declare it using my and we don't want to always prefix it with the package name.
With use vars ('$x') we can achieve that:
- use strict ;
- package VeryLongName ;
- use vars ( '$x' );
- $x = 23 ;
- print "VeryLongName: $x\n" ;
This works, but the documentation of vars tells us that the functionality provided by this pragma has been superseded by "our" declarations .
So how does our work?
ourCaveat
- use strict ;
- package VeryLongName ;
- our $x = 23 ;
- print "VeryLongName: $x\n" ;
The our declaration itself is lexically scoped, meaning it is limited by the file or by enclosing curly braces. In the next example we don't have curly braces and thus the declaration our $x = 23; will be intact even after switching namespaces. This can lead to very unpleasant situations. My recommendation is to avoid using our (you almost always need to use my anyway) and to put every package in its own file.
- use strict ;
- package VeryLongName ;
- our $x = 23 ;
- print "VeryLongName: $x\n" ; # VeryLongName: 23
- package main ;
- print "$x\n" ; # 23
Oct 09, 2019 | stackoverflow.com
Asked 10 years, 5 months ago Active 3 years, 1 month ago Viewed 107k times 180 56
Nathan Fellman ,May 10, 2009 at 10:24
I know whatmy
is in Perl. It defines a variable that exists only in the scope of the block in which it is defined. What doesour
do? How doesour
differ frommy
?Nathan Fellman ,Nov 20, 2016 at 1:15
Great question: How doesour
differ frommy
and what doesour
do?In Summary:
Available since Perl 5,
my
is a way to declare:
- non-package variables, that are
- private,
- new ,
- non-global variables,
- separate from any package. So that the variable cannot be accessed in the form of
$package_name::variable
.
On the other hand,
our
variables are:
- package variables, and thus automatically
- global variables,
- definitely not private ,
- nor are they necessarily new; and they
- can be accessed outside the package (or lexical scope) with the qualified namespace, as
$package_name::variable
.
Declaring a variable with
our
allows you to predeclare variables in order to use them underuse strict
without getting typo warnings or compile-time errors. Since Perl 5.6, it has replaced the obsoleteuse vars
, which was only file-scoped, and not lexically scoped as isour
.For example, the formal, qualified name for variable
$x
insidepackage main
is$main::x
. Declaringour $x
allows you to use the bare$x
variable without penalty (i.e., without a resulting error), in the scope of the declaration, when the script usesuse strict
oruse strict "vars"
. The scope might be one, or two, or more packages, or one small block.Georg ,Oct 1, 2016 at 6:41
The PerlMonks and PerlDoc links from cartman and Olafur are a great reference - below is my crack at a summary:
my
variables are lexically scoped within a single block defined by{}
or within the same file if not in{}
s. They are not accessible from packages/subroutines defined outside of the same lexical scope / block.
our
variables are scoped within a package/file and accessible from any code thatuse
orrequire
that package/file - name conflicts are resolved between packages by prepending the appropriate namespace.Just to round it out,
local
variables are "dynamically" scoped, differing frommy
variables in that they are also accessible from subroutines called within the same block.Nathan Fellman ,Nov 20, 2015 at 18:46
An example:use strict; for (1 .. 2){ # Both variables are lexically scoped to the block. our ($o); # Belongs to 'main' package. my ($m); # Does not belong to a package. # The variables differ with respect to newness. $o ++; $m ++; print __PACKAGE__, " >> o=$o m=$m\n"; # $m is always 1. # The package has changed, but we still have direct, # unqualified access to both variables, because the # lexical scope has not changed. package Fubb; print __PACKAGE__, " >> o=$o m=$m\n"; } # The our() and my() variables differ with respect to privacy. # We can still access the variable declared with our(), provided # that we fully qualify its name, but the variable declared # with my() is unavailable. print __PACKAGE__, " >> main::o=$main::o\n"; # 2 print __PACKAGE__, " >> main::m=$main::m\n"; # Undefined. # Attempts to access the variables directly won't compile. # print __PACKAGE__, " >> o=$o\n"; # print __PACKAGE__, " >> m=$m\n"; # Variables declared with use vars() are like those declared # with our(): belong to a package; not private; and not new. # However, their scoping is package-based rather than lexical. for (1 .. 9){ use vars qw($uv); $uv ++; } # Even though we are outside the lexical scope where the # use vars() variable was declared, we have direct access # because the package has not changed. print __PACKAGE__, " >> uv=$uv\n"; # And we can access it from another package. package Bubb; print __PACKAGE__, " >> main::uv=$main::uv\n";daotoad ,May 10, 2009 at 16:37
Coping with Scoping is a good overview of Perl scoping rules. It's old enough thatour
is not discussed in the body of the text. It is addressed in the Notes section at the end.The article talks about package variables and dynamic scope and how that differs from lexical variables and lexical scope.
Chas. Owens ,Oct 7, 2013 at 14:02
my is used for local variables, where as our is used for global variables. More reading over Variable Scoping in Perl: the basics .ruffin ,Feb 10, 2015 at 19:47
It's an old question, but I ever met some pitfalls about lexical declarations in Perl that messed me up, which are also related to this question, so I just add my summary here:1. definition or declaration?
local $var = 42; print "var: $var\n";The output is
var: 42
. However we couldn't tell iflocal $var = 42;
is a definition or declaration. But how about this:use strict; use warnings; local $var = 42; print "var: $var\n";The second program will throw an error:
Global symbol "$var" requires explicit package name.
$var
is not defined, which meanslocal $var;
is just a declaration! Before usinglocal
to declare a variable, make sure that it is defined as a global variable previously.But why this won't fail?
use strict; use warnings; local $a = 42; print "var: $a\n";The output is:
var: 42
.That's because
$a
, as well as$b
, is a global variable pre-defined in Perl. Remember the sort function?2. lexical or global?
I was a C programmer before starting using Perl, so the concept of lexical and global variables seems straightforward to me: just corresponds to auto and external variables in C. But there're small differences:
In C, an external variable is a variable defined outside any function block. On the other hand, an automatic variable is a variable defined inside a function block. Like this:
int global; int main(void) { int local; }While in Perl, things are subtle:
sub main { $var = 42; } &main; print "var: $var\n";The output is
var: 42
,$var
is a global variable even it's defined in a function block! Actually in Perl, any variable is declared as global by default.The lesson is to always add
use strict; use warnings;
at the beginning of a Perl program, which will force the programmer to declare the lexical variable explicitly, so that we don't get messed up by some mistakes taken for granted.Ólafur Waage ,May 10, 2009 at 10:25
The perldoc has a good definition of our.Unlike my, which both allocates storage for a variable and associates a simple name with that storage for use within the current scope, our associates a simple name with a package variable in the current package, for use within the current scope. In other words, our has the same scoping rules as my, but does not necessarily create a variable.
Cosmicnet ,Nov 22, 2014 at 13:57
This is only somewhat related to the question, but I've just discovered a (to me) obscure bit of perl syntax that you can use with "our" (package) variables that you can't use with "my" (local) variables.#!/usr/bin/perl our $foo = "BAR"; print $foo . "\n"; ${"foo"} = "BAZ"; print $foo . "\n";Output:
BAR BAZThis won't work if you change 'our' to 'my'.
Okuma.Scott ,Sep 6, 2014 at 20:13
print "package is: " . __PACKAGE__ . "\n"; our $test = 1; print "trying to print global var from main package: $test\n"; package Changed; { my $test = 10; my $test1 = 11; print "trying to print local vars from a closed block: $test, $test1\n"; } &Check_global; sub Check_global { print "trying to print global var from a function: $test\n"; } print "package is: " . __PACKAGE__ . "\n"; print "trying to print global var outside the func and from \"Changed\" package: $test\n"; print "trying to print local var outside the block $test1\n";Will Output this:
package is: main trying to print global var from main package: 1 trying to print local vars from a closed block: 10, 11 trying to print global var from a function: 1 package is: Changed trying to print global var outside the func and from "Changed" package: 1 trying to print local var outside the blockIn case using "use strict" will get this failure while attempting to run the script:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24. Execution of ./check_global.pl aborted due to compilation errors.Nathan Fellman ,Nov 5, 2015 at 14:03
Just try to use the following program :#!/usr/local/bin/perl use feature ':5.10'; #use warnings; package a; { my $b = 100; our $a = 10; print "$a \n"; print "$b \n"; } package b; #my $b = 200; #our $a = 20 ; print "in package b value of my b $a::b \n"; print "in package b value of our a $a::a \n";Nathan Fellman ,May 16, 2013 at 11:07
#!/usr/bin/perl -l use strict; # if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee' #my $lol = 'eeeeeeeeeee' ; # no errors or warnings at any case, despite of 'strict' our $lol = eval {$lol} || 'lol' ; print $lol;Evgeniy ,Jan 27, 2016 at 4:57
Let us think what an interpreter actually is: it's a piece of code that stores values in memory and lets the instructions in a program that it interprets access those values by their names, which are specified inside these instructions. So, the big job of an interpreter is to shape the rules of how we should use the names in those instructions to access the values that the interpreter stores.On encountering "my", the interpreter creates a lexical variable: a named value that the interpreter can access only while it executes a block, and only from within that syntactic block. On encountering "our", the interpreter makes a lexical alias of a package variable: it binds a name, which the interpreter is supposed from then on to process as a lexical variable's name, until the block is finished, to the value of the package variable with the same name.
The effect is that you can then pretend that you're using a lexical variable and bypass the rules of 'use strict' on full qualification of package variables. Since the interpreter automatically creates package variables when they are first used, the side effect of using "our" may also be that the interpreter creates a package variable as well. In this case, two things are created: a package variable, which the interpreter can access from everywhere, provided it's properly designated as requested by 'use strict' (prepended with the name of its package and two colons), and its lexical alias.
Sources:
Oct 09, 2019 | stackoverflow.com
Perl Import Package in different Namespace Ask Question Asked 1 year ago Active 7 months ago Viewed 150 times We're doing things differently. View all 8 job openings! 2
choroba ,Sep 28, 2018 at 22:17
is it possible to import (use
) a perl module within a different namespace?Let's say I have a Module
A
(XS Module with no methods Exported@EXPORT
is empty) and I have no way of changing the module.This Module has a Method
A::open
currently I can use that Module in my main program (package main) by calling
A::open
I would like to have that module inside mypackage main
so that I can directly callopen
I tried to manually push every key of
%A::
into%main::
however that did not work as expected.The only way that I know to achieve what I want is by using
package A;
inside my main program, effectively changing the package of my program frommain
toA
. Im not satisfied with this. I would really like to keep my program inside package main.Is there any way to achieve this and still keep my program in package main?
Offtopic: Yes I know usually you would not want to import everything into your namespace but this module is used by us extensively and we don't want to type A:: (well the actual module name is way longer which isn't making the situation better)in front of hundreds or thousands of calls
Grinnz ,Oct 1, 2018 at 6:26
This is one of those "impossible" situations, where the clear solution -- to rework that module -- is off limits.But, you can alias that package's subs names, from its symbol table, to the same names in
main
. Worse than being rude, this comes with a glitch: it catches all names that that package itself imported in any way. However, since this package is a fixed quantity it stands to reason that you can establish that list (and even hard-code it). It is just this one time, right?main
use warnings; use strict; use feature 'say'; use OffLimits; GET_SUBS: { # The list of names to be excluded my $re_exclude = qr/^(?:BEGIN|import)$/; # ... my @subs = grep { !/$re_exclude/ } sort keys %OffLimits::; no strict 'refs'; for my $sub_name (@subs) { *{ $sub_name } = \&{ 'OffLimits::' . $sub_name }; } }; my $name = name('name() called from ' . __PACKAGE__); my $id = id('id() called from ' . __PACKAGE__); say "name() returned: $name"; say "id() returned: $id";with
OffLimits.pm
package OffLimits; use warnings; use strict; sub name { return "In " . __PACKAGE__ . ": @_" } sub id { return "In " . __PACKAGE__ . ": @_" } 1;It prints
name() returned: In OffLimits: name() called from main id() returned: In OffLimits: id() called from mainYou may need that code in a
BEGIN
block, depending on other details.Another option is of course to hard-code the subs to be "exported" (in
@subs
). Given that the module is in practice immutable this option is reasonable and more reliable.
This can also be wrapped in a module, so that you have the normal, selective, importing.
WrapOffLimits.pm
package WrapOffLimits; use warnings; use strict; use OffLimits; use Exporter qw(import); our @sub_names; our @EXPORT_OK = @sub_names; our %EXPORT_TAGS = (all => \@sub_names); BEGIN { # Or supply a hard-coded list of all module's subs in @sub_names my $re_exclude = qr/^(?:BEGIN|import)$/; # ... @sub_names = grep { !/$re_exclude/ } sort keys %OffLimits::; no strict 'refs'; for my $sub_name (@sub_names) { *{ $sub_name } = \&{ 'OffLimits::' . $sub_name }; } }; 1;and now in the caller you can import either only some subs
use WrapOffLimits qw(name);or all
use WrapOffLimits qw(:all);with otherwise the same main as above for a test.
The module name is hard-coded, which should be OK as this is meant only for that module.
The following is added mostly for completeness.
One can pass the module name to the wrapper by writing one's own
import
sub, which is what gets used then. The import list can be passed as well, at the expense of an awkward interface of theuse
statement.It goes along the lines of
package WrapModule; use warnings; use strict; use OffLimits; use Exporter qw(); # will need our own import our ($mod_name, @sub_names); our @EXPORT_OK = @sub_names; our %EXPORT_TAGS = (all => \@sub_names); sub import { my $mod_name = splice @_, 1, 1; # remove mod name from @_ for goto my $re_exclude = qr/^(?:BEGIN|import)$/; # etc no strict 'refs'; @sub_names = grep { !/$re_exclude/ } sort keys %{ $mod_name . '::'}; for my $sub_name (@sub_names) { *{ $sub_name } = \&{ $mod_name . '::' . $sub_name }; } push @EXPORT_OK, @sub_names; goto &Exporter::import; } 1;what can be used as
use WrapModule qw(OffLimits name id); # or (OffLimits :all)or, with the list broken-up so to remind the user of the unusual interface
use WrapModule 'OffLimits', qw(name id);When used with the main above this prints the same output.
The
use
statement ends up using the import sub defined in the module, which exports symbols by writing to the caller's symbol table. (If noimport
sub is written then theExporter
'simport
method is nicely used, which is how this is normally done.)This way we are able to unpack the arguments and have the module name supplied at
use
invocation. With the import list supplied as well now we have topush
manually to@EXPORT_OK
since this can't be in theBEGIN
phase. In the end the sub is replaced byExporter::import
via the (good form of) goto , to complete the job.Simerax ,Sep 30, 2018 at 10:19
You can forcibly "import" a function into main using glob assignment to alias the subroutine (and you want to do it in BEGIN so it happens at compile time, before calls to that subroutine are parsed later in the file):use strict; use warnings; use Other::Module; BEGIN { *open = \&Other::Module::open }However, another problem you might have here is that open is a builtin function, which may cause some problems . You can add
use subs 'open';
to indicate that you want to override the built-in function in this case, since you aren't using an actual import function to do so.Grinnz ,Sep 30, 2018 at 17:33
Here is what I now came up with. Yes this is hacky and yes I also feel like I opened pandoras box with this. However at least a small dummy program ran perfectly fine.I renamed the module in my code again. In my original post I used the example
A::open
actually this module does not contain any method/variable reserved by the perl core. This is why I blindly import everything here.BEGIN { # using the caller to determine the parent. Usually this is main but maybe we want it somewhere else in some cases my ($parent_package) = caller; package A; foreach (keys(%A::)) { if (defined $$_) { eval '*'.$parent_package.'::'.$_.' = \$A::'.$_; } elsif (%$_) { eval '*'.$parent_package.'::'.$_.' = \%A::'.$_; } elsif (@$_) { eval '*'.$parent_package.'::'.$_.' = \@A::'.$_; } else { eval '*'.$parent_package.'::'.$_.' = \&A::'.$_; } } }
Oct 09, 2019 | stackoverflow.com
Perl Importing Variables From Calling Module Ask Question Asked 9 years, 1 month ago Active 9 years, 1 month ago Viewed 4k times 0 1
Russell C. ,Aug 31, 2010 at 20:31
I have a Perl module (Module.pm) that initializes a number of variables, some of which I'd like to import ($VAR2, $VAR3) into additional submodules that it might load during execution.The way I'm currently setting up Module.pm is as follows:
package Module; use warnings; use strict; use vars qw($SUBMODULES $VAR1 $VAR2 $VAR3); require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw($VAR2 $VAR3); sub new { my ($package) = @_; my $self = {}; bless ($self, $package); return $self; } sub SubModules1 { my $self = shift; if($SUBMODULES->{'1'}) { return $SUBMODULES->{'1'}; } # Load & cache submodule require Module::SubModule1; $SUBMODULES->{'1'} = Module::SubModule1->new(@_); return $SUBMODULES->{'1'}; } sub SubModules2 { my $self = shift; if($SUBMODULES->{'2'}) { return $SUBMODULES->{'2'}; } # Load & cache submodule require Module::SubModule2; $SUBMODULES->{'2'} = Module::SubModule2->new(@_); return $SUBMODULES->{'2'}; }Each submodule is structured as follows:
package Module::SubModule1; use warnings; use strict; use Carp; use vars qw(); sub new { my ($package) = @_; my $self = {}; bless ($self, $package); return $self; }I want to be able to import the $VAR2 and $VAR3 variables into each of the submodules without having to reference them as $Module::VAR2 and $Module::VAR3. I noticed that the calling script is able to access both the variables that I have exported in Module.pm in the desired fashion but SubModule1.pm and SubModule2.pm still have to reference the variables as being from Module.pm.
I tried updating each submodule as follows which unfortunately didn't work I was hoping:
package Module::SubModule1; use warnings; use strict; use Carp; use vars qw($VAR2 $VAR3); sub new { my ($package) = @_; my $self = {}; bless ($self, $package); $VAR2 = $Module::VAR2; $VAR3 = $Module::VAR3; return $self; }Please let me know how I can successfully export $VAR2 and $VAR3 from Module.pm into each Submodule. Thanks in advance for your help!
Russell C. ,Aug 31, 2010 at 22:37
In your submodules, are you forgetting to sayuse Module;? Calling
use Module
from another package (sayModule::Submodule9
) will try to run theModule::import
method. Since you don't have that method, it will call theExporter::import
method, and that is where the magic that exportsModule
's variables into theModule::Submodule9
namespace will happen.
In your program there is only one
Module
namespace and only one instance of the (global) variable$Module::VAR2
. Exporting creates aliases to this variable in other namespaces, so the same variable can be accessed in different ways. Try this in a separate script:package Whatever; use Module; use strict; use vars qw($VAR2); $Module::VAR2 = 5; print $Whatever::VAR2; # should be 5. $VAR2 = 14; # same as $Whatever::VAR2 = 14 print $Module::VAR2; # should be 14Russell C. ,Aug 31, 2010 at 21:38
Well there is the easy way:In M.pm:
package M; use strict; use warnings; #our is better than "use vars" for creating package variables #it creates an alias to $M::foo named $foo in the current lexical scope our $foo = 5; sub inM { print "$foo\n" } 1;In M/S.pm
package M; #creates an alias to $M::foo that will last for the entire scope, #in this case the entire file our $foo; package M::S; use strict; use warnings; sub inMS { print "$foo\n" } 1;In the script:
#!/usr/bin/perl use strict; use warnings; use M; use M::S; M::inM(); M::S::inMS();But I would advise against this. Global variables are not a good practice, and sharing global variables between modules is even worse.
Oct 09, 2019 | perlmaven.com
These are the oldest type of variables in Perl. They are still used in some cases, even though in most cases you should just use lexical variables.
In old times, if we started to use a variable without declaring it with the my or state keywords, we automatically got a variable in the current namespace. Thus we could write:
- $x = 42 ;
- print "$x\n" ; # 42
Please note, we don't use strict; in these examples. Even though you should always use strict . We'll fix this in a bit.
The default namespace in every perl script is called "main" and you can always access variables using their full name including the namespace:
- $x = 42 ;
- print "$x\n" ; # 42
- print "$main::x\n" ; # 42
The package keyword is used to switch namespaces:
- $x = 42 ;
- print "$x\n" ; # 42
- print "$main::x\n" ; # 42
- package Foo ;
- print "Foo: $x\n" ; # Foo:
Please note, once we switched to the "Foo" namespace, the $x name refers to the variable in the Foo namespace. It does not have any value yet.
- $x = 42 ;
- print "$x\n" ; # 42
- print "$main::x\n" ; # 42
- package Foo ;
- print "Foo: $x\n" ; # Foo:
- $x = 23 ;
- print "Foo: $x\n" ; # Foo 23;
Do we really have two $x-es? Can we reach the $x in the main namespace while we are in the Foo namespace?
- $x = 42 ;
- print "$x\n" ; # 42
- print "$main::x\n" ; # 42
- package Foo ;
- print "Foo: $x\n" ; # Foo:
- $x = 23 ;
- print "Foo: $x\n" ; # Foo 23
- print "main: $main::x\n" ; # main: 42
- print "Foo: $Foo::x\n" ; # Foo: 23
- package main ;
- print "main: $main::x\n" ; # main: 42
- print "Foo: $Foo::x\n" ; # Foo: 23
- print "$x\n" ; # 42
We even switched back to the main namespace (using package main; ) and if you look closely, you can see that while we were already in the main package we could reach to the $x of the Foo package using $Foo::x but if we accessed $x without the full package name, we reach the one in the main namespace.
Every package (or namespace) can hold variables with the same name.
Oct 08, 2019 | stackoverflow.com
Ask Question Asked 6 years, 1 month ago Active 4 years ago Viewed 5k times 4 1
Alec ,Sep 5, 2018 at 8:25
use constant { COLUMNS => qw/ TEST1 TEST2 TEST3 /, }Can I store an array using the constant package in Perl?
Whenever I go on to try to use the array like
my @attr = (COLUMNS);
, it does not contain the values.Сухой27 ,Aug 12, 2013 at 13:37
use constant { COLUMNS => [qw/ TEST1 TEST2 TEST3 /], }; print @{+COLUMNS};> ,
Or remove the curly braces as the docs show :-1 use strict; 2 use constant COLUMNS => qw/ TEST1 TEST2 TEST3 /; 3 4 my @attr = (COLUMNS); 5 print @attr;which gives :-
% perl test.pl TEST1TEST2TEST3Your code actually defines two constants COLUMNS and TEST2 :-
use strict; use constant { COLUMNS => qw/ TEST1 TEST2 TEST3 /, }; my @attr = (COLUMNS); print @attr; print TEST2and gives :-
% perl test.pl TEST1TEST3
Sep 30, 2019 | perldoc.perl.org
- int EXPR
- int
Returns the integer portion of EXPR. If EXPR is omitted, uses $_ . You should not use this function for rounding: one because it truncates towards
0
, and two because machine representations of floating-point numbers can sometimes produce counterintuitive results.For example,
int(-6.725/0.025)
produces -268 rather than the correct -269; that's because it's really more like -268.99999999999994315658 instead.Usually, the sprintf , printf , or the POSIX::floor and POSIX::ceil functions will serve you better than will int .
Sep 24, 2019 | perldoc.perl.org
Perl 5 version 30.0 documentation warn Perl functions A-Z | Perl functions by category | The 'perlfunc' manpage
- warn LIST
Emits a warning, usually by printing it to
STDERR
.warn
interprets its operand LIST in the same way asdie
, but is slightly different in what it defaults to when LIST is empty or makes an empty string. If it is empty and $@ already contains an exception value then that value is used after appending"\t...caught"
. If it is empty and$@
is also empty then the string"Warning: Something's wrong"
is used.By default, the exception derived from the operand LIST is stringified and printed to
STDERR
. This behaviour can be altered by installing a $SIG{__WARN__} handler. If there is such a handler then no message is automatically printed; it is the handler's responsibility to deal with the exception as it sees fit (like, for instance, converting it into a die ). Most handlers must therefore arrange to actually display the warnings that they are not prepared to deal with, by calling warn again in the handler. Note that this is quite safe and will not produce an endless loop, since__WARN__
hooks are not called from inside one.You will find this behavior is slightly different from that of $SIG{__DIE__} handlers (which don't suppress the error text, but can instead call die again to change it).
Using a
__WARN__
handler provides a powerful way to silence all warnings (even the so-called mandatory ones). An example:
- # wipe out *all* compile-time warnings
- BEGIN { $SIG { '__WARN__' } = sub { warn $_ [ 0 ] if $DOWARN } }
- my $foo = 10 ;
- my $foo = 20 ; # no warning about duplicate my $foo,
- # but hey, you asked for it!
- # no compile-time or run-time warnings before here
- $DOWARN = 1 ;
- # run-time warnings enabled after here
- warn "\$foo is alive and $foo!" ; # does show up
See perlvar for details on setting %SIG entries and for more examples. See the Carp module for other kinds of warnings using its
carp
andcluck
functions.
Sep 21, 2019 | perl.plover.com
Coping with Scoping
© Copyright 1998 The Perl Journal. Reprinted with permission.
Cet article est également disponible en Français
Questo articolo è disponibile anche in Italiano
Dieser Artikel ist auch in deutscher Übersetzung verfügbar
Just the FAQs: Coping with ScopingIn the Beginning, some time around 1960, every part of your program had access to all the variables in every other part of the program. That turned out to be a problem, so language designers invented local variables, which were visible in only a small part of the program. That way, programmers who used a variable x could be sure that nobody was able to tamper with the contents of x behind their back. They could also be sure that by using x they weren't tampering with someone else's variable by mistake.
Every programming language has a philosophy, and these days most of these philosophies have to do with the way the names of variables are managed. Details of which variables are visible to which parts of the program, and what names mean what, and when, are of prime importance. The details vary from somewhat baroque, in languages like Lisp, to extremely baroque, in languages like C++. Perl unfortunately, falls somewhere towards the rococo end of this scale.
The problem with Perl isn't that it has no clearly-defined system of name management, but rather that it two systems, both working at once. Here's the Big Secret about Perl variables that most people learn too late: Perl has two completely separate, independent sets of variables. One is left over from Perl 4, and the other is new. The two sets of variables are called `package variables' and `lexical variables', and they have nothing to do with each other.
Package variables came first, so we'll talk about them first. Then we'll see some problems with package variables, and how lexical variables were introduced in Perl 5 to avoid these problems. Finally, we'll see how to get Perl to automatically diagnose places where you might not be getting the variable you meant to get, which can find mistakes before they turn into bugs.
Package Variables$x = 1Here, $x is a package variable . There are two important things to know about package variables:
- Package variables are what you get if you don't say otherwise.
- Package variables are always global.
Global means that package variables are always visible everywhere in every program. After you do $x = 1 , any other part of the program, even some other subroutine defined in some other file, can inspect and modify the value of $x . There's no exception to this; package variables are always global.
Package variables are divided into families, called packages . Every package variable has a name with two parts. The two parts are analogous to the variable's given name and family name. You can call the Vice-President of the United States `Al', if you want, but that's really short for his full name, which is `Al Gore'. Similarly, $x has a full name, which is something like $main::x . The main part is the package qualifier , analogous to the `Gore' part of `Al Gore'. Al Gore and Al Capone are different people even though they're both named `Al'. In the same way, $Gore::Al and $Capone::Al are different variables, and $main::x and $DBI::x are different variables.
You're always allowed to include the package part of the variable's name, and if you do, Perl will know exactly which variable you mean. But for brevity, you usually like to leave the package qualifier off. What happens if you do?
The Current PackageIf you just say $x , perl assumes that you mean the variable $x in the current package. What's the current package? It's normally main , but you can change the current package by writing
package Mypackage;in your program; from that point on, the current package is Mypackage . The only thing the current package does is affect the interpretation of package variables that you wrote without package names. If the current package is Mypackage , then $x really means $Mypackage::x . If the current package is main , then $x really means $main::x.
If you were writing a module, let's say the MyModule module, you would probably put a line like this at the top of the module file:
package MyModule;From there on, all the package variables you used in the module file would be in package MyModule , and you could be pretty sure that those variables wouldn't conflict with the variables in the rest of the program. It wouldn't matter if both you and the author of DBI were to use a variable named $x , because one of those $x es would be $MyModule::x and the other would be $DBI::x .
Remember that package variables are always global. Even if you're not in package DBI, even if you've never heard of package DBI, nothing can stop you from reading from or writing to $DBI::errstr . You don't have to do anything special. $DBI::errstr , like all package variables, is a global variable, and it's available globally; all you have to do is mention its full name to get it. You could even say
package DBI; $errstr = 'Ha ha Tim!';and that would modify $DBI::errstr .
Package Variable TriviaThere are only three other things to know about package variables, and you might want to skip them on the first reading:
- The package with the empty name is the same as main . So $::x is the same as $main::x for any x .
- Some variables are always forced to be in package main. For example, if you mention %ENV , Perl assumes that you mean %main::ENV , even if the current package isn't main . If you want %Fred::ENV , you have to say so explicitly, even if the current package is Fred . Other names that are special this way include INC , all the one-punctuation-character names like $_ and $$ , @ARGV , and STDIN , STDOUT , and STDERR .
- Package names, but not variable names, can contain :: . You can have a variable named $DBD::Oracle::x. This means the variable x in the package DBD::Oracle ; it has nothing at all to do with the package DBD which is unrelated. Isaac Newton is not related to Olivia Newton-John, and Newton::Isaac is not related to Newton::John::Olivia . Even though it appears that they both begin with Newton , the appearance is deceptive. Newton::John::Olivia is in package Newton::John , not package Newton.
That's all there is to know about package variables.
Package variables are global, which is dangerous, because you can never be sure that someone else isn't tampering with them behind your back. Up through Perl 4, all variables were package variables, which was worrisome. So Perl 5 added new variables that aren't global.
Lexical VariablesPerl's other set of variables are called lexical variables (we'll see why later) or private variables because they're private. They're also sometimes called my variables because they're always declared with my . It's tempting to call them `local variables', because their effect is confined to a small part of the program, but don't do that, because people might think you're talking about Perl's local operator, which we'll see later. When you want a `local variable', think my , not local .
The declaration
my $x;creates a new variable, named x , which is totally inaccessible to most parts of the program---anything outside the block where the variable was declared. This block is called the scope of the variable. If the variable wasn't declared in any block, its scope is from the place it was declared to the end of the file.
You can also declare and initialize a my variable by writing something like
my $x = 119;You can declare and initialize several at once:
my ($x, $y, $z, @args) = (5, 23, @_);Let's see an example of where some private variables will be useful. Consider this subroutine:
sub print_report { @employee_list = @_; foreach $employee (@employee_list) { $salary = lookup_salary($employee); print_partial_report($employee, $salary); } }If lookup_salary happens to also use a variable named $employee , that's going to be the same variable as the one used in print_report , and the works might get gummed up. The two programmers responsible for print_report and lookup_salary will have to coordinate to make sure they don't use the same variables. That's a pain. In fact, in even a medium-sized project, it's an intolerable pain.
The solution: Use my variables:
sub print_report { my @employee_list = @_; foreach my $employee (@employee_list) { my $salary = lookup_salary($employee); print_partial_report($employee, $salary); } }my @employee_list creates a new array variable which is totally inaccessible outside the print_report function. for my $employee creates a new scalar variable which is totally inaccessible outside the foreach loop, as does my $salary . You don't have to worry that the other functions in the program are tampering with these variables, because they can't; they don't know where to find them, because the names have different meanings outside the scope of the my declarations. These `my variables' are sometimes called `lexical' because their scope depends only on the program text itself, and not on details of execution, such as what gets executed in what order. You can determine the scope by inspecting the source code without knowing what it does. Whenever you see a variable, look for a my declaration higher up in the same block. If you find one, you can be sure that the variable is inaccessible outside that block. If you don't find a declaration in the smallest block, look at the next larger block that contains it, and so on, until you do find one. If there is no my declaration anywhere, then the variable is a package variable.
my variables are not package variables. They're not part of a package, and they don't have package qualifiers. The current package has no effect on the way they're interpreted. Here's an example:
my $x = 17; package A; $x = 12; package B; $x = 20; # $x is now 20. # $A::x and $B::x are still undefinedThe declaration my $x = 17 at the top creates a new lexical variable named x whose scope continues to the end of the file. This new meaning of $x overrides the default meaning, which was that $x meant the package variable $x in the current package.
package A changes the current package, but because $x refers to the lexical variable, not to the package variable, $x=12 doesn't have any effect on $A::x . Similarly, after package B , $x=20 modifies the lexical variable, and not any of the package variables.
At the end of the file, the lexical variable $x holds 20, and the package variables $main::x , $A::x , and $B::x are still undefined. If you had wanted them, you could still have accessed them by using their full names.
The maxim you must remember is:
Package variables are global variables.
local and my
For private variables, you must use my .Almost everyone already knows that there's a local function that has something to do with local variables. What is it, and how does it related to my ? The answer is simple, but bizarre:
my creates a local variable. local doesn't.
First, here's what local $x really does: It saves the current value of the package variable $x in a safe place, and replaces it with a new value, or with undef if no new value was specified. It also arranges for the old value to be restored when control leaves the current block. The variables that it affects are package variables, which get local values. But package variables are always global, and a local package variable is no exception. To see the difference, try this:
$lo = 'global'; $m = 'global'; A(); sub A { local $lo = 'AAA'; my $m = 'AAA'; B(); } sub B { print "B ", ($lo eq 'AAA' ? 'can' : 'cannot') , " see the value of lo set by A.\n"; print "B ", ($m eq 'AAA' ? 'can' : 'cannot') , " see the value of m set by A.\n"; }This prints
B can see the value of lo set by A. B cannot see the value of m set by A.What happened here? The local declaration in A saved a new temporary value, AAA , in the package variable $lo . The old value, global , will be restored when A returns, but before that happens, A calls B . B has no problem accessing the contents of $lo , because $lo is a package variable and package variables are always available everywhere, and so it sees the value AAA set by A .
In contrast, the my declaration created a new, lexically scoped variable named $m , which is only visible inside of function A . Outside of A , $m retains its old meaning: It refers the the package variable $m ; which is still set to global . This is the variable that B sees. It doesn't see the AAA because the variable with that value is a lexical variable, and only exists inside of A .
What Good is local ?Because local does not actually create local variables, it is not very much use. If, in the example above, B happened to modify the value of $lo , then the value set by A would be overwritten. That is exactly what we don't want to happen. We want each function to have its own variables that are untouchable by the others. This is what my does.
Why have local at all? The answer is 90% history. Early versions of Perl only had global variables. local was very easy to implement, and was added to Perl 4 as a partial solution to the local variable problem. Later, in Perl 5, more work was done, and real local variables were put into the language. But the name local was already taken, so the new feature was invoked with the word my . my was chosen because it suggests privacy, and also because it's very short; the shortness is supposed to encourage you to use it instead of local . my is also faster than local .
When to Use my and When to Use localAlways use my ; never use local .
Wasn't that easy?
Other Properties of my VariablesEvery time control reaches a my declaration, Perl creates a new, fresh variable. For example, this code prints x=1 fifty times:
for (1 .. 50) { my $x; $x++; print "x=$x\n"; }You get a new $x , initialized to undef , every time through the loop.
If the declaration were outside the loop, control would only pass by it once, so there would only be one variable:
{ my $x; for (1 .. 50) { $x++; print "x=$x\n"; } }This prints x=1 , x=2 , x=3 , ... x=50 .
You can use this to play a useful trick. Suppose you have a function that needs to remember a value from one call to the next. For example, consider a random number generator. A typical random number generator (like Perl's rand function) has a seed in it. The seed is just a number. When you ask the random number generator for a random number, the function performs some arithmetic operation that scrambles the seed, and it returns the result. It also saves the result and uses it as the seed for the next time it is called.
Here's typical code: (I stole it from the ANSI C standard, but it behaves poorly, so don't use it for anything important.)
$seed = 1; sub my_rand { $seed = int(($seed * 1103515245 + 12345) / 65536) % 32768; return $seed; }And typical output:
16838 14666 10953 11665 7451 26316 27974 27550There's a problem here, which is that $seed is a global variable, and that means we have to worry that someone might inadvertently tamper with it. Or they might tamper with it on purpose, which could affect the rest of the program. What if the function were used in a gambling program, and someone tampered with the random number generator?
But we can't declare $seed as a my variable in the function:
sub my_rand { my $seed; $seed = int(($seed * 1103515245 + 12345) / 65536) % 32768; return $seed; }If we did, it would be initialized to undef every time we called my_rand . We need it to retain its value between calls to my_rand .
Here's the solution:
{ my $seed = 1; sub my_rand { $seed = int(($seed * 1103515245 + 12345) / 65536) % 32768; return $seed; } }The declaration is outside the function, so it only happens once, at the time the program is compiled, not every time the function is called. But it's a my variable, and it's in a block, so it's only accessible to code inside the block. my_rand is the only other thing in the block, so the $seed variable is only accessible to the my_rand function.
$seed here is sometimes called a `static' variable, because it stays the same in between calls to the function. (And because there's a similar feature in the C language that is activated by the static keyword.)
my Variable TriviaDeclarations
- You can't declare a variable my if its name is a punctuation character, like $_ , @_ , or $$ . You can't declare the backreference variables $1 , $2 , ... as my . The authors of my thought that that would be too confusing.
- Obviously, you can't say my $DBI::errstr , because that's contradictory---it says that the package variable $DBI::errstr is now a lexical variable. But you can say local $DBI::errstr ; it saves the current value of $DBI::errstr and arranges for it to be restored at the end of the block.
- New in Perl 5.004, you can write
foreach my $i (@list) {instead, to confine the $i to the scope of the loop instead. Similarly,
for (my $i=0; $i<100; $i++) {confines the scope of $i to the for loop.
If you're writing a function, and you want it to have private variables, you need to declare the variables with my . What happens if you forget?
sub function { $x = 42; # Oops, should have been my $x = 42. }In this case, your function modifies the global package variable $x . If you were using that variable for something else, it could be a disaster for your program.
Recent versions of Perl have an optional protection against this that you can enable if you want. If you put
use strict 'vars';at the top of your program, Perl will require that package variables have an explicit package qualifier. The $x in $x=42 has no such qualifier, so the program won't even compile; instead, the compiler will abort and deliver this error message:
Global symbol "$x" requires explicit package name at ...If you wanted $x to be a private my variable, you can go back and add the my . If you really wanted to use the global package variable, you could go back and change it to
$main::x = 42;or whatever would be appropriate.
Just saying use strict turns on strict vars , and several other checks besides. See perldoc strict for more details.
Now suppose you're writing the Algorithms::KnuthBendix modules, and you want the protections of strict vars But you're afraid that you won't be able to finish the module because your fingers are starting to fall off from typing $Algorithms::KnuthBendix::Error all the time.
You can save your fingers and tell strict vars to make an exception:
package Algorithms::KnuthBendix; use vars '$Error';This exempts the package variable $Algorithms::KnuthBendix::Error from causing a strict vars failure if you refer to it by its short name, $Error .
You can also turn strict vars off for the scope of one block by writing
{ no strict 'vars'; # strict vars is off for the rest of the block. }SummaryPackage variables are always global. They have a name and a package qualifier. You can omit the package qualifier, in which case Perl uses a default, which you can set with the package declaration. For private variables, use my . Don't use local ; it's obsolete.
You should avoid using global variables because it can be hard to be sure that no two parts of the program are using one another's variables by mistake.
To avoid using global variables by accident, add use strict 'vars' to your program. It checks to make sure that all variables are either declared private, are explicitly qualified with package qualifiers, or are explicitly declared with use vars .
Glossary
- global variable
- global
- lexical variable
- local declaration
- my
- my declaration
- my variable
- package declaration
- package qualifier
- package variable
- private variable
- scope
- use strict vars
- use vars
Notes
- The tech editors complained about my maxim `Never use local .' But 97% of the time, the maxim is exactly right. local has a few uses, but only a few, and they don't come up too often, so I left them out, because the whole point of a tutorial article is to present 97% of the utility in 50% of the space.
I was still afraid I'd get a lot of tiresome email from people saying ``You forgot to mention that local can be used for such-and-so, you know.'' So in the colophon at the end of the article, I threatened to deliver Seven Useful Uses for local in three months. I mostly said it to get people off my back about local . But it turned out that I did write it, and it was published some time later.
The Seven Useful Uses of local is now available on the web site. It appeared in The Perl Journal issue #14.
- Here's another potentially interesting matter that I left out for space and clarity. I got email from Robert Watkins with a program he was writing that didn't work. The essence of the bug looked like this:
my $x; for $x (1..5) { s(); } sub s { print "$x, " }Robert wanted this to print 1, 2, 3, 4, 5, but it did not. Instead, it printed , , , , , . Where did the values of $x go?
The deal here is that normally, when you write something like this:
for $x (...) { }Perl wants to confine the value of the index variable to inside the loop. If $x is a package variable, it pretends that you wrote this instead:
{ local $x; for $x (...) { } }But if $x is a lexical variable, it pretends you wrote this instead, instead:
{ my $x; for $x (...) { } }This means that the loop index variable won't get propagated to subroutines, even if they're in the scope of the original declaration.
I probably shouldn't have gone on at such length, because the perlsyn manual page describes it pretty well:
...the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with my , it uses that variable instead of the global one, but it's still localized to the loop. (Note that a lexically scoped variable can cause problems if you have subroutine or format declarations within the loop which refer to it.)In my opinion, lexically scoping the index variable was probably a mistake. If you had wanted that, you would have written for my $x ... in the first place. What I would have liked it to do was to localize the lexical variable: It could save the value of the lexical variable before the loop, and restore it again afterwards. But there may be technical reasons why that couldn't be done, because this doesn't work either:
my $m; { local $m = 12; ... }The local fails with this error message:
Can't localize lexical variable $m...There's been talk on P5P about making this work, but I gather it's not trivial.
- Added 2000-01-05: Perl 5.6.0 introduced a new our(...) declaration. Its syntax is the same as for my() , and it is a replacement for use vars .
Without getting into the details, our() is just like use vars ; its only effect is to declare variables so that they are exempt from the strict 'vars' checking. It has two possible advantages over use vars , however: Its syntax is less weird, and its effect is lexical. That is, the exception that it creates to the strict checking continues only to the end of the current block:
use strict 'vars'; { our($x); $x = 1; # Use of global variable $x here is OK } $x = 2; # Use of $x here is a compile-time error as usualSo whereas use vars '$x' declares that it is OK to use the global variable $x everywhere, our($x) allows you to say that global $x should be permitted only in certain parts of your program, and should still be flagged as an error if you accidentally use it elsewhere.
- Added 2000-01-05: Here's a little wart that takes people by surprise. Consider the following program:
use strict 'vars'; my @lines = <>; my @sorted = sort backwards @lines; print @sorted; sub backwards { $b cmp $a }Here we have not declared $a or $b , so they are global variables. In fact, they have to be global, because the sort operator must to be able to set them up for the backwards function. Why doesn't strict produce a failure?
The variables $a and $b are exempted from strict vars checking, for exactly this reason.
Sep 21, 2019 | www.tutorialspoint.com
What are Packages?
The Package Statement
- A package is a collection of code which lives in its own namespace
- A namespace is a named collection of unique variable names (also called a symbol table).
- Namespaces prevent variable name collisions between packages
- Packages enable the construction of modules which, when used, won't clobbber variables and functions outside of the modules's own namespace
package statement switches the current naming context to a specified namespace (symbol table) - If the named package does not exists, a new namespace is first created.
$i = 1; print "$i\n"; # Prints "1" package foo; $i = 2; print "$i\n"; # Prints "2" package main; print "$i\n"; # Prints "1"
- The package stays in effect until either another package statement is invoked, or until the end of the end of the current block or file.
- You can explicitly refer to variables within a package using the :: package qualifier
$PACKAGE_NAME::VARIABLE_NAME For Example: $i = 1; print "$i\n"; # Prints "1" package foo; $i = 2; print "$i\n"; # Prints "2" package main; print "$i\n"; # Prints "1" print "$foo::i\n"; # Prints "2"BEGIN and END BlocksYou may define any number of code blocks named BEGIN and END which act as constructors and destructors respectively.
BEGIN { ... } END { ... } BEGIN { ... } END { ... }What are Perl Modules?
- Every BEGIN block is executed after the perl script is loaded and compiled but before any other statement is executed
- Every END block is executed just before the perl interpreter exits.
- The BEGIN and END blocks are particularly useful when creating Perl modules.
A Perl module is a reusable package defined in a library file whose name is the same as the name of the package (with a .pm on the end).
A Perl module file called "Foo.pm" might contain statements like this.
#!/usr/bin/perl package Foo; sub bar { print "Hello $_[0]\n" } sub blat { print "World $_[0]\n" } 1;Few noteable points about modules
The Require Function
- The functions require and use will load a module.
- Both use the list of search paths in @INC to find the module (you may modify it!)
- Both call the eval function to process the code
- The 1; at the bottom causes eval to evaluate to TRUE (and thus not fail)
A module can be loaded by calling the require function
#!/usr/bin/perl require Foo; Foo::bar( "a" ); Foo::blat( "b" );Notice above that the subroutine names must be fully qualified (because they are isolated in their own package)
It would be nice to enable the functions bar and blat to be imported into our own namespace so we wouldn't have to use the Foo:: qualifier.
The Use FunctionA module can be loaded by calling the use function
#!/usr/bin/perl use Foo; bar( "a" ); blat( "b" );Notice that we didn't have to fully qualify the package's function names?
The use function will export a list of symbols from a module given a few added statements inside a module
require Exporter; @ISA = qw(Exporter);Then, provide a list of symbols (scalars, lists, hashes, subroutines, etc) by filling the list variable named @EXPORT : For Example
package Module; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(bar blat); sub bar { print "Hello $_[0]\n" } sub blat { print "World $_[0]\n" } sub splat { print "Not $_[0]\n" } # Not exported! 1;Create the Perl Module TreeWhen you are ready to ship your PERL module then there is standard way of creating a Perl Module Tree. This is done using h2xs utility. This utility comes alongwith PERL. Here is the syntax to use h2xs
$h2xs -AX -n Module Name # For example, if your module is available in Person.pm file $h2xs -AX -n Person This will produce following result Writing Person/lib/Person.pm Writing Person/Makefile.PL Writing Person/README Writing Person/t/Person.t Writing Person/Changes Writing Person/MANIFESTHere is the descritpion of these options
- -A omits the Autoloader code (best used by modules that define a large number of infrequently used subroutines)
- -X omits XS elements (eXternal Subroutine, where eXternal means external to Perl, i.e. C)
- -n specifies the name of the module
So above command creates the following structure inside Person directory. Actual result is shown above.
- Changes
- Makefile.PL
- MANIFEST (contains the list of all files in the package)
- README
- t/ (test files)
- lib/ ( Actual source code goes here
So finally you tar this directory structure into a file Person.tar and you can ship it. You would have to update README file with the proper instructions. You can provide some test examples files in t directory.
Installing Perl ModuleInstalling a Perl Module is very easy. Use the following sequence to install any Perl Module.
perl Makefile.PL make make installThe Perl interpreter has a list of directories in which it searches for modules (global array @INC)
Feb 26, 2006 | perl.org.il
Irrationalities in Other Languages (5:54)
Now, I'm not the only language designer with irrationalities. You can think of some languages to go with some of these things.
"We've got to start over from scratch" - Well, that's almost any academic language you find.
"English phrases" - We'll that's Cobol. You know, cargo cult English. ( laughter )
"Text processing doesn't matter much" - Fortran.
"Simple languages produce simple solutions" - C.
"If I wanted it fast, I'd write it in C" - That's almost a direct quote from the original awk page.
"I thought of a way to do it so it must be right" - That's obviously PHP. ( laughter and applause )
"You can build anything with NAND gates" - Any language designed by an electrical engineer. ( laughter )
"This is a very high level language, who cares about bits?" - The entire scope of fourth generation languages fell into this... problem.
"Users care about elegance" - A lot of languages from Europe tend to fall into this. You know, Eiffel.
"The specification is good enough" - Ada.
"Abstraction equals usability" - Scheme. Things like that.
"The common kernel should be as small as possible" - Forth.
"Let's make this easy for the computer" - Lisp. ( laughter )
"Most programs are designed top-down" - Pascal. ( laughter )
"Everything is a vector" - APL.
"Everything is an object" - Smalltalk and its children. (whispered:) Ruby. ( laughter )
"Everything is a hypothesis" - Prolog. ( laughter )
"Everything is a function" - Haskell. ( laughter )
"Programmers should never have been given free will" - Obviously, Python. ( laughter )
So my psychological conjecture is that normal people, if they perceive that a computer language is forcing them to learn theory, they won't like it. In other words, hide the fancy stuff. It can be there, just hide it. Fan Mail (14:42)
- Q: "Dear Larry, I love Perl. It has saved my company, my crew, my sanity and my marriage. After Perl I can't imagine going back to any other language. I dream in Perl, I tell everyone else about Perl. How can you improve on perfection? Signed, Happy in Haifa."
- A: "Dear Happy,
- You need to recognize that Perl can be good in some dimensions and not so good in other dimensions. You also need to recognize that there will be some pain in climbing over or tunneling through the barrier to the true minimum."
Now Perl 5 has a few false minima. Syntax, semantics, pragmatics, ( laughter ), discourse structure, implementation, documentation, culture... Other than that Perl 5 is not too bad.
- Q: "Dear Larry,
- You have often talked about the waterbed theory of linguistic complexity, and beauty times brains equals a constant. Isn't it true that improving Perl in some areas will automatically make it worse in other areas? Signed, Terrified in Tel-Aviv."
- A: "Dear Terrified,
- ...
- No." ( laughter )
You see, you can make some things so they aren't any worse. For instance, we changed all the sigils to be more consistent, and they're just the same length, they're just different. And you can make some things much better. Instead of having to write all this gobbledygook to dereference references in Perl 5 you can just do it straight left to right in Perl 6. Or there's even more shortcuts, so multidimensional arrays and constant hash subscripts get their own notation, so it's even clearer, at least once you've learned it. Again, we're optimizing for expressiveness, not necessarily learnability.
- Q: "Dear Larry,
- I've heard a disturbing rumor that Perl 6 is turning into Java, or Python, or (whispered:) Ruby, or something. What's the point of using Perl if it's just another object-oriented language? Why are we changing the arrow operator to the dot operator? Signed, Nervous in Netanya."
- A: "Dear Nervous,
- First of all, we can do object orientation better without making other things worse. As I said. Now, we're changing from arrow to dot, because ... because ... Well, just 'cuz I said so!"
You know, actually, we do have some good reasons - it's shorter, it's the industry standard, I wanted the arrow for something else, and I wanted the dot as a secondary sigil. Now we can have it for attributes that have accessors. I also wanted the unary dot for topical type calls, with an assumed object on the left and finally, because I said so. Darn it.
... ... ...
No arbitrary limits round two : Perl started off with the idea that strings should grow infinitely, if you have memory. Just let's get rid of those arbitrary limits that plagued Unix utilities in the early years. Perl 6 is taking this in a number of different dimensions than just how long your strings are. No arbitrary limits - you ought to be able to program very abstractly, you ought to be able to program very concretely - that's just one dimension.
... .. ...
Perl 5 is just all full of these strange gobbledygooky variables which we all know and love - and hate. So the error variables are now unified into a single error variable. These variables have been deprecated forever, they're gone! These weird things that just drive syntax highlighters nuts ( laughter ) now actually have more regular names. The star there, $*GID, that's what we call a secondary sigil, what that just says is this is in the global namespace. So we know that that's a global variable for the entire process. Similarly for uids.
... ... ...
Perl 5 had this problem with "do" loops because they weren't real loops - they were a "do" block followed by a statement modifier, and people kept wanting to use loop control it them. Well, we can fix that. "loop" now is a real loop. And it allows a modifier on it but still behaves as a real loop. And so, do goes off to have other duties, and you can write a loop that tests at the end and it is a real loop. And this is just one of many many many things that confused new Perl 5 programmers.
... ... ...
Perl 5, another place where it was too orthogonal - we defined parameter passing to just come in as an array. You know arrays, subroutines - they're just orthogonal. You just happen to have one called @_, which your parameters come in, and it was wonderfully orthogonal, and people built all sorts of stuff on top of it, and it's another place where we are changing.
... .. ...
Likewise, if you turn them inside out - the french quotes - you can use the regular angle brackets, and yes, we did change here-docs so it does not conflict, then that's the equivalent of "qw". This qw interpolates, with single-angles it does not interpolate - that is the exact "qw".We have properties which you can put on variables and onto values. These are generalizations of things that were special code in Perl 5, but now we have general mechanisms to do the same things, they're actually done using a mix-in mechanism like Ruby.
Smart match operators is, like Damian say, equal-tilda ("=~") on steroids. Instead of just allowing a regular expression on the right side it allows basically anything, and it figures out that this wants to do a numeric comparison, this wants to do a string comparison, this wants to compare two arrays, this wants to do a lookup in the hash; this wants to call the closure on the right passing in the left argument, and it will tell if you if $x can quack. Now that looks a little strange because you can just say "$x.can('quack')". Why would you do it this way? Well, you'll see.
... ... ..
There's a lot of cruft that we inherited from the UNIX culture and we added more cruft, and we're cleaning it up. So in Perl 5 we made the mistake of interpreting regular expressions as strings, which means we had to do weird things like back-references are \1 on the left, but they're $1 on the right, even though it means the same thing. In Perl 6, because it's just a language, (an embedded language) $1 is the back-reference. It does not automatically interpolate this $1 from what it was before. You can also get it translated to Euros I guess.
Feb 28, 1998 | www.ddj.com
... ... ...
The creator of Perl talks about language design and Perl. By Eugene Eric Kim
DDJ : Is Perl 5.005 what you envisioned Perl to be when you set out to do it?
LW: That assumes that I'm smart enough to envision something as complicated as Perl. I knew that Perl would be good at some things, and would be good at more things as time went on. So, in a sense, I'm sort of blessed with natural stupidity -- as opposed to artificial intelligence -- in the sense that I know what my intellectual limits are.
I'm not one of these people who can sit down and design an entire system from scratch and figure out how everything relates to everything else, so I knew from the start that I had to take the bear-of-very-little-brain approach, and design the thing to evolve. But that fit in with my background in linguistics, because natural languages evolve over time.
You can apply biological metaphors to languages. They move into niches, and as new needs arise, languages change over time. It's actually a practical way to design a computer language. Not all computer programs can be designed that way, but I think more can be designed that way than have been. A lot of the majestic failures that have occurred in computer science have been because people thought they could design the whole thing in advance.
DDJ : How do you design a language to evolve?
LW: There are several aspects to that, depending on whether you are talking about syntax or semantics. On a syntactic level, in the particular case of Perl, I placed variable names in a separate namespace from reserved words. That's one of the reasons there are funny characters on the front of variable names -- dollar signs and so forth. That allowed me to add new reserved words without breaking old programs.
DDJ : What is a scripting language? Does Perl fall into the category of a scripting language?
LW: Well, being a linguist, I tend to go back to the etymological meanings of "script" and "program," though, of course, that's fallacious in terms of what they mean nowadays. A script is what you hand to the actors, and a program is what you hand to the audience. Now hopefully, the program is already locked in by the time you hand that out, whereas the script is something you can tinker with. I think of phrases like "following the script," or "breaking from the script." The notion that you can evolve your script ties into the notion of rapid prototyping.
A script is something that is easy to tweak, and a program is something that is locked in. There are all sorts of metaphorical tie-ins that tend to make programs static and scripts dynamic, but of course, it's a continuum. You can write Perl programs, and you can write C scripts. People do talk more about Perl programs than C scripts. Maybe that just means Perl is more versatile.
... ... ...
DDJ : Would that be a better distinction than interpreted versus compiled -- run-time versus compile-time binding?
LW: It's a more useful distinction in many ways because, with late-binding languages like Perl or Java, you cannot make up your mind about what the real meaning of it is until the last moment. But there are different definitions of what the last moment is. Computer scientists would say there are really different "latenesses" of binding.
A good language actually gives you a range, a wide dynamic range, of your level of discipline. We're starting to move in that direction with Perl. The initial Perl was lackadaisical about requiring things to be defined or declared or what have you. Perl 5 has some declarations that you can use if you want to increase your level of discipline. But it's optional. So you can say "use strict," or you can turn on warnings, or you can do various sorts of declarations.
DDJ : Would it be accurate to say that Perl doesn't enforce good design?
LW: No, it does not. It tries to give you some tools to help if you want to do that, but I'm a firm believer that a language -- whether it's a natural language or a computer language -- ought to be an amoral artistic medium.
You can write pretty poems or you can write ugly poems, but that doesn't say whether English is pretty or ugly. So, while I kind of like to see beautiful computer programs, I don't think the chief virtue of a language is beauty. That's like asking an artist whether they use beautiful paints and a beautiful canvas and a beautiful palette. A language should be a medium of expression, which does not restrict your feeling unless you ask it to.
DDJ : Where does the beauty of a program lie? In the underlying algorithms, in the syntax of the description?
LW: Well, there are many different definitions of artistic beauty. It can be argued that it's symmetry, which in a computer language might be considered orthogonality. It's also been argued that broken symmetry is what is considered most beautiful and most artistic and diverse. Symmetry breaking is the root of our whole universe according to physicists, so if God is an artist, then maybe that's his definition of what beauty is.
This actually ties back in with the built-to-evolve concept on the semantic level. A lot of computer languages were defined to be naturally orthogonal, or at least the computer scientists who designed them were giving lip service to orthogonality. And that's all very well if you're trying to define a position in a space. But that's not how people think. It's not how natural languages work. Natural languages are not orthogonal, they're diagonal. They give you hypotenuses.
Suppose you're flying from California to Quebec. You don't fly due east, and take a left turn over Nashville, and then go due north. You fly straight, more or less, from here to there. And it's a network. And it's actually sort of a fractal network, where your big link is straight, and you have little "fractally" things at the end for your taxi and bicycle and whatever the mode of transport you use. Languages work the same way. And they're designed to get you most of the way here, and then have ways of refining the additional shades of meaning.
When they first built the University of California at Irvine campus, they just put the buildings in. They did not put any sidewalks, they just planted grass. The next year, they came back and built the sidewalks where the trails were in the grass. Perl is that kind of a language. It is not designed from first principles. Perl is those sidewalks in the grass. Those trails that were there before were the previous computer languages that Perl has borrowed ideas from. And Perl has unashamedly borrowed ideas from many, many different languages. Those paths can go diagonally. We want shortcuts. Sometimes we want to be able to do the orthogonal thing, so Perl generally allows the orthogonal approach also. But it also allows a certain number of shortcuts, and being able to insert those shortcuts is part of that evolutionary thing.
I don't want to claim that this is the only way to design a computer language, or that everyone is going to actually enjoy a computer language that is designed in this way. Obviously, some people speak other languages. But Perl was an experiment in trying to come up with not a large language -- not as large as English -- but a medium-sized language, and to try to see if, by adding certain kinds of complexity from natural language, the expressiveness of the language grew faster than the pain of using it. And, by and large, I think that experiment has been successful.
DDJ : Give an example of one of the things you think is expressive about Perl that you wouldn't find in other languages.
LW: The fact that regular-expression parsing and the use of regular expressions is built right into the language. If you used the regular expression in a list context, it will pass back a list of the various subexpressions that it matched. A different computer language may add regular expressions, even have a module that's called Perl 5 regular expressions, but it won't be integrated into the language. You'll have to jump through an extra hoop, take that right angle turn, in order to say, "Okay, well here, now apply the regular expression, now let's pull the things out of the regular expression," rather than being able to use the thing in a particular context and have it do something meaningful.
The school of linguistics I happened to come up through is called tagmemics, and it makes a big deal about context. In a real language -- this is a tagmemic idea -- you can distinguish between what the conventional meaning of the "thing" is and how it's being used. You think of "dog" primarily as a noun, but you can use it as a verb. That's the prototypical example, but the "thing" applies at many different levels. You think of a sentence as a sentence. Transformational grammar was built on the notion of analyzing a sentence. And they had all their cute rules, and they eventually ended up throwing most of them back out again.
But in the tagmemic view, you can take a sentence as a unit and use it differently. You can say a sentence like, "I don't like your I-can-use-anything-like-a-sentence attitude." There, I've used the sentence as an adjective. The sentence isn't an adjective if you analyze it, any way you want to analyze it. But this is the way people think. If there's a way to make sense of something in a particular context, they'll do so. And Perl is just trying to make those things make sense. There's the basic distinction in Perl between singular and plural context -- call it list context and scalar context, if you will. But you can use a particular construct in a singular context that has one meaning that sort of makes sense using the list context, and it may have a different meaning that makes sense in the plural context.
That is where the expressiveness comes from. In English, you read essays by people who say, "Well, how does this metaphor thing work?" Owen Barfield talks about this. You say one thing and mean another. That's how metaphors arise. Or you take two things and jam them together. I think it was Owen Barfield, or maybe it was C.S. Lewis, who talked about "a piercing sweetness." And we know what "piercing" is, and we know what "sweetness" is, but you put those two together, and you've created a new meaning. And that's how languages ought to work.
DDJ : Is a more expressive language more difficult to learn?
LW: Yes. It was a conscious tradeoff at the beginning of Perl that it would be more difficult to master the whole language. However, taking another clue from a natural language, we do not require 5-year olds to speak with the same diction as 50-year olds. It is okay for you to use the subset of a language that you are comfortable with, and to learn as you go. This is not true of so many computer-science languages. If you program C++ in a subset that corresponds to C, you get laughed out of the office.
There's a whole subject that we haven't touched here. A language is not a set of syntax rules. It is not just a set of semantics. It's the entire culture surrounding the language itself. So part of the cultural context in which you analyze a language includes all the personalities and people involved -- how everybody sees the language, how they propagate the language to other people, how it gets taught, the attitudes of people who are helping each other learn the language -- all of this goes into the pot of context.
Because I had already put out other freeware projects (rn and patch), I realized before I ever wrote Perl that a great deal of the value of those things was from collaboration. Many of the really good ideas in rn and Perl came from other people.
I think that Perl is in its adolescence right now. There are places where it is grown up, and places where it's still throwing tantrums. I have a couple of teenagers, and the thing you notice about teenagers is that they're always plus or minus ten years from their real age. So if you've got a 15-year old, they're either acting 25 or they're acting 5. Sometimes simultaneously! And Perl is a little that way, but that's okay.
DDJ : What part of Perl isn't quite grown up?
LW: Well, I think that the part of Perl, which has not been realistic up until now has been on the order of how you enable people in certain business situations to actually use it properly. There are a lot of people who cannot use freeware because it is, you know, schlocky. Their bosses won't let them, their government won't let them, or they think their government won't let them. There are a lot of people who, unknown to their bosses or their government, are using Perl.
DDJ : So these aren't technical issues.
LW: I suppose it depends on how you define technology. Some of it is perceptions, some of it is business models, and things like that. I'm trying to generate a new symbiosis between the commercial and the freeware interests. I think there's an artificial dividing line between those groups and that they could be more collaborative.
As a linguist, the generation of a linguistic culture is a technical issue. So, these adjustments we might make in people's attitudes toward commercial operations or in how Perl is being supported, distributed, advertised, and marketed -- not in terms of trying to make bucks, but just how we propagate the culture -- these are technical ideas in the psychological and the linguistic sense. They are, of course, not technical in the computer-science sense. But I think that's where Perl has really excelled -- its growth has not been driven solely by technical merits.
DDJ : What are the things that you do when you set out to create a culture around the software that you write?
LW: In the beginning, I just tried to help everybody. Particularly being on USENET. You know, there are even some sneaky things in there -- like looking for people's Perl questions in many different newsgroups. For a long time, I resisted creating a newsgroup for Perl, specifically because I did not want it to be ghettoized. You know, if someone can say, "Oh, this is a discussion about Perl, take it over to the Perl newsgroup," then they shut off the discussion in the shell newsgroup. If there are only the shell newsgroups, and someone says, "Oh, by the way, in Perl, you can solve it like this," that's free advertising. So, it's fuzzy. We had proposed Perl as a newsgroup probably a year or two before we actually created it. It eventually came to the point where the time was right for it, and we did that.
DDJ : Perl has really been pigeonholed as a language of the Web. One result is that people mistakenly try to compare Perl to Java. Why do you think people make the comparison in the first place? Is there anything to compare?
LW: Well, people always compare everything.
DDJ : Do you agree that Perl has been pigeonholed?
LW: Yes, but I'm not sure that it bothers me. Before it was pigeonholed as a web language, it was pigeonholed as a system-administration language, and I think that -- this goes counter to what I was saying earlier about marketing Perl -- if the abilities are there to do a particular job, there will be somebody there to apply it, generally speaking. So I'm not too worried about Perl moving into new ecological niches, as long as it has the capability of surviving in there.
Perl is actually a scrappy language for surviving in a particular ecological niche. (Can you tell I like biological metaphors?) You've got to understand that it first went up against C and against shell, both of which were much loved in the UNIX community, and it succeeded against them. So that early competition actually makes it quite a fit competitor in many other realms, too.
For most web applications, Perl is severely underutilized. Your typical CGI script says print, print, print, print, print, print, print. But in a sense, it's the dynamic range of Perl that allows for that. You don't have to say a whole lot to write a simple Perl script, whereas your minimal Java program is, you know, eight or ten lines long anyway. Many of the features that made it competitive in the UNIX space will make it competitive in other spaces.
Now, there are things that Perl can't do. One of the things that you can't do with Perl right now is compile it down to Java bytecode. And if that, in the long run, becomes a large ecological niche (and this is not yet a sure thing), then that is a capability I want to be certain that Perl has.
DDJ : There's been a movement to merge the two development paths between the ActiveWare Perl for Windows and the main distribution of Perl. You were talking about ecological niches earlier, and how Perl started off as a text-processing language. The scripting languages that are dominant on the Microsoft platforms -- like VB -- tend to be more visual than textual. Given Perl's UNIX origins -- awk, sed, and C, for that matter -- do you think that Perl, as it currently stands, has the tools to fit into a Windows niche?
LW: Yes and no. It depends on your problem domain and who's trying to solve the problem. There are problems that only need a textual solution or don't need a visual solution. Automation things of certain sorts don't need to interact with the desktop, so for those sorts of things -- and for the programmers who aren't really all that interested in visual programming -- it's already good for that. And people are already using it for that. Certainly, there is a group of people who would be enabled to use Perl if it had more of a visual interface, and one of the things we're talking about doing for the O'Reilly NT Perl Resource Kit is some sort of a visual interface.
A lot of what Windows is designed to do is to get mere mortals from 0 to 60, and there are some people who want to get from 60 to 100. We are not really interested in being in Microsoft's crosshairs. We're not actually interested in competing head-to-head with Visual Basic, and to the extent that we do compete with them, it's going to be kind of subtle. There has to be some way to get people from the slow lane to the fast lane. It's one thing to give them a way to get from 60 to 100, but if they have to spin out to get from the slow lane to the fast lane, then that's not going to work either.
Over the years, much of the work of making Perl work for people has been in designing ways for people to come to Perl. I actually delayed the first version of Perl for a couple of months until I had a sed-to-Perl and an awk-to-Perl translator. One of the benefits of borrowing features from various other languages is that those subsets of Perl that use those features are familiar to people coming from that other culture. What would be best, in my book, is if someone had a way of saying, "Well, I've got this thing in Visual Basic. Now, can I just rewrite some of these things in Perl?"
We're already doing this with Java. On our UNIX Perl Resource Kit, I've got a hybrid language called "jpl" -- that's partly a pun on my old alma mater, Jet Propulsion Laboratory, and partly for Java, Perl...Lingo, there we go! That's good. "Java Perl Lingo." You've heard it first here! jpl lets you take a Java program and magically turn one of the methods into a chunk of Perl right there inline. It turns Perl code into a native method, and automates the linkage so that when you pull in the Java code, it also pulls in the Perl code, and the interpreter, and everything else. It's actually calling out from Java's Virtual Machine into Perl's virtual machine. And we can call in the other direction, too. You can embed Java in Perl, except that there's a bug in JDK having to do with threads that prevents us from doing any I/O. But that's Java's problem.
It's a way of letting somebody evolve from a purely Java solution into, at least partly, a Perl solution. It's important not only to make Perl evolve, but to make it so that people can evolve their own programs. It's how I program, and I think a lot of people program that way. Most of us are too stupid to know what we want at the beginning.
DDJ : Is there hope down the line to present Perl to a standardization body?
LW: Well, I have said in jest that people will be free to standardize Perl when I'm dead. There may come a time when that is the right thing to do, but it doesn't seem appropriate yet.
DDJ : When would that time be?
LW: Oh, maybe when the federal government declares that we can't export Perl unless it's standardized or something.
DDJ : Only when you're forced to, basically.
LW: Yeah. To me, once things get to a standards body, it's not very interesting anymore. The most efficient form of government is a benevolent dictatorship. I remember walking into some BOF that USENIX held six or seven years ago, and John Quarterman was running it, and he saw me sneak in, sit in the back corner, and he said, "Oh, here comes Larry Wall! He's a s