Message Boards Message Boards

1
|
27035 Views
|
18 Replies
|
17 Total Likes
View groups...
Share
Share this post:

How to define constants?

Posted 7 years ago

Programming languages normally allow to define some kind of constants, i.e. names for some constant values which cannot be changed and have a scope throughout a program, some package, module or the like.

I could not find something like that in WL until now. On a system level there are these constants, e.g. "Pi, E" and the like. But how can I define this kind of things myself?

Of course I know, that I can do that with "With[{myConst=3},...]". This is ok for some few lines of local coding. But I would not like to pack my large notebooks within some strange With-Function, just to define some primitive constant.

There must be some better way, and I hope you tell me, how to define some global constant like "Pi" for my own purposes.

POSTED BY: Werner Geiger
18 Replies

Suppose you wanted to define a constant whose value was Zeta[3], and call it AperysConstant. If you want to make AperysConstant behave like E, Pi, etc., you would do:

SetAttributes[AperysConstant, Constant];
NumericQ[AperysConstant] = True;
N[AperysConstant, _] = Zeta[3];

Then, AperysConstant behaves like Pi. Below I give some examples:

N

N[AperysConstant]
N[Pi]

N[AperysConstant, 20]
N[Pi, 20]

(* 1.20206 *)
(* 3.14159 *)

(* 1.2020569031595942854 *)
(* 3.1415926535897932385 *)

Dt

Dt[x^AperysConstant,x]
Dt[x^Pi, x]
Dt[x^y, x]

(* AperysConstant x^(-1+AperysConstant) *)
(* \[Pi] x^(-1+\[Pi]) *)
(* x^y (y/x+Dt[y,x] Log[x]) *)

Note the difference between AperysConstant and y above.

Less

 1 < AperysConstant < 2
 3 < Pi < 4

(* True *)
(* True *)

Sign

 Sign[AperysConstant-2]
 Sign[Pi-4]

(* -1 *)
(* -1 *)

Inexact arithmetic

 AperysConstant + 1.1`20
 Pi + 1.1`20

(* 2.3020569031595942854 *)
(* 4.2415926535897932385 *)

Variables

Variables[1 + Pi x + x^2]
Variables[1 + AperysConstant x + x^2]

(* {x} *)
(* {x} *)
POSTED BY: Carl Woll
Posted 7 years ago

Just an example how this could be done:

declareConstant[name_Symbol, value_] := (name = value; Protect@name;
  Print[ToString@Unevaluated@name <> " = " <> ToString@name])

Then:

enter image description here

To organize the constants they could all be declared in a separate context, say Constants`. But at the moment I don't get the code for this to work.

POSTED BY: Hans Milton

seems to me it's a lot easier to define your constant as a variable and then write your code so it doesn't get changed.

POSTED BY: Frank Kampas
Posted 7 years ago

Sorry Frank, but this is not the point.

If someone ever wrote a large program with some 100.000 lines of code and some 10 developers and had a lot of global variables therein, he knows what a nightmare that becomes. Global variables are a nightmare in any case because of their far reaching unknown influence. And to expect some global variable to stay unchanged, i.e. a constant, is practically nonsense. But even if you assure by naming conventions or the like, that everybody knows, what is global and what is even constant, you will never succeed. Since people do not respect rules which they can break.

That is why many tens of years ago somebody invented objected-oriented programming. Just to shield data from being changed unexpectedly.

POSTED BY: Werner Geiger

I work on a substantially larger program. I've written that many lines, with a few to spare. As regards defining constants in WL, setting the Protected and perhapsLocked attribute(s) is a good idea. Use of a "function", as in @SanderHuisman's approach, is fine for some purposes, perhaps overkill for others.

Short of With[{...}...] style macroization of values, there is no support for creating absolutely immutable "constants". What we most often do involves locking symbols, sometimes exported from specialized contexts. Works well. Not worth trying to make something so simple absolutely foolproof; if your project team is going to mess it up, your problem is with the team.

As for localizing variables vs. maintaining globals, this is largely a separate issue, and there is no doubt that having globals in use can cause trouble. Best I think is to use lists or Association or other structures that encapsulate variable lists. I agree that having "globals" that are constants is acceptable.

POSTED BY: Daniel Lichtblau
Posted 7 years ago

I had to read your comment several times to understand it. Now I think your comment ist helpful, and we agree. Apart from "encapsulating globals into lists or associations or anything else". For me it doesn't change anything in which data structure you store global data. As long as those globals are freely, i. e. directly available as pure data to everybody they are dangerous. They have to be encapsulated into objects/functions. Probably you ment to say the same.

Hence: Defining constants as ordinary, but protected variables would be the best way in WL? I feel so as well.

Those Macro-mechanisms known from standard language preprocessors, witch are nothing but text-processing are obviously not available in WL.

POSTED BY: Werner Geiger
Posted 7 years ago

Thanks to everybody.

@Frank: This is not a constant, just a normal variable, which can by changed by anything throughout the program. That is of course what I am doing at the moment, but makes me unhappy.

n = 2;

@Sander: Sounds reasonable, but somewhat strange. Is there really nothing like a constant datatype within WL? Hence define a normal global symbol and then protect it? But ok, why not?

n=2;SetAttributes[n,{Constant,Protected}]

@David: Explicitly replace constants through coding wherever they appear? That's a joke. It would make the coding unreadable.

mm 3 + bb /. constants

@Sam: Read the docs, I know. I did that. Maybe with your explicit links I can get nearer to that trivial feature of defining a constant.

For the moment I think, Sanders method is the best.

POSTED BY: Werner Geiger
Anonymous User
Anonymous User
Posted 7 years ago

This is not a constant, just a normal variable, which can by changed by anything throughout the program.

"Protect" seems like what you're looking for? That is how the system does it for Pi and E, I think.

POSTED BY: Anonymous User

Alternatively, it can be done by defining a function with 0 arity (nullary):

Unprotect[MyConstant]
ClearAll[MyConstant]
N[MyConstant[],p_:{MachinePrecision, MachinePrecision}] := N[Log[2],p]
SetAttributes[MyConstant,{NumericFunction,Constant,Protected}]

MyConstant[]  (* remains unevaluated *)
Positive[MyConstant[]]  (* positive will trigger an N and then return True *)
NumericQ[MyConstant[]] (* NumericQ 'reads' the NumericFunction attribute *)

MyConstant[]+1.0    (* constant + machine precision number will trigger numeric evaluation of the constant *)
MyConstant[]+1.0`100 (* will trigger appropriate numerical evaluation *)
POSTED BY: Sander Huisman
Posted 7 years ago

Whow! Your coding looks horrible and unreadable without careful reengineering. What an effort just for a simple constant.

Why not something simple like the following? Should be within WL of course, but if that or something similar does not exist there, then self written as lower case "constant"-function with help of your SetAttributes... from above.

cIdxStart=Constant[1];
cStrStart=Constant[Row[{"Start, i=",cIdxStart}]]; 
POSTED BY: Werner Geiger

Because of the symbolic nature and dynamic typing of WL it is not that easy. Something can be 'constant', but non-numeric (think e.g. a string, a formula, a symbol, or ...). So functions like derivative and Positive, NumericQ have to 'act' differently depending on the type. Note that Attributes plays a vital role in the WL and also note that the first two of my lines are strictly not needed.

What do you want to do with it? if you just want to have a 'variable' which can not be changed, you could simply use Protect[...] (equivalent to SetAttributes[...,Protected]). If you want it to correctly interact with Dt and so on, you have to specify more 'stuff'. To sum up:

With great symbolic computation comes great carefulness

POSTED BY: Sander Huisman
Posted 7 years ago

Hmm, @Sander, this seems to be more difficult than I thought at first.

I want to have some named object, e.g. myConst, after being defined to stay constant throughout some scope, say a notebook or a notebook-section or the like, and being replaced in my code by its value - whatever that is - whenever this name appears. Similar to With[{myConst=...},...]. But without bracketing all that scope.

Defined by something like myConst=Constant[...].

At first I thought that your Protect-mechanism for a normal variable myConst would do all I want. But now after reading your comment and thinking about what all the other programming languages do, I am no more sure. Maybe I just want to have this kind of pure text-replacement which classical languages like C, C++ do during their pre-compile processing.

POSTED BY: Werner Geiger

Hello Sander,

why do you write

N[MyConstant[],p_:{MachinePrecision, MachinePrecision}] := N[Log[2],p]

the MachinePrecison twice?

POSTED BY: Hans Dolhaine

The default value is exactly that:

N~Default~2
{MachinePrecision, MachinePrecision}

So I just copied that...

POSTED BY: Sander Huisman

You should take a look at Contexts and generally some quite educational set of tutorials Modularity and the Naming of Things.

POSTED BY: Sam Carrettie
Posted 7 years ago

I use two different methods. If it is a few constants that really will be constant, and I am wiling to re-evaluate the entire notebook to change them, then I do as Frank suggests and just set their values at the beginning of the notebook in a well defined place. On the other hand, if I want different values at different places, or if I want to preserve the ability to work with them symbolically, I define my set of constants with a list of rules, and use replace to access them when numerical values are wanted.

In[5]:= m = 2; b = -1;

In[6]:= constants = {mm -> 2, bb -> -1};

In[7]:= m 3 + b

Out[7]= 5

In[8]:= mm 3 + bb /. constants

Out[8]= 5
POSTED BY: David Keith

n = 2;

POSTED BY: Frank Kampas

And in addition, one could set the appropriate Attributes like e.g. Pi:

SetAttributes[n,{Constant,Protected}]
POSTED BY: Sander Huisman
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract