Codedom Variable Assignments

'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write(''); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
    '); newwindow.document.write('
  • Paul Kimmel
  • '); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('

pkimmel@softconcepts.com

'); newwindow.document.write('

Close this window

'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write('
'); newwindow.document.write(''); newwindow.document.write(''); if (window.focus) {newwindow.focus()} }
  • Send Email »
  • More Articles »
  • The first part of this article introduced the macro steps involved in creating a code generator with Microsoft's .NET CodeDOM. This powerful part of the framework is already used to generate a strongly typed DataSet from an XML Schema (integrated into the IDE and found in the XSD.exe utility), create client side proxies for XML Web Services (again, integrated into the IDE and found in the WSDL.exe utility), and several other places inside the framework.

    In this second half of the article, we'll create a code generator that generates all of the code for a Windows Form. While not earth shaking, it could very well be the basis for a Windows application generator or a clever wizard and will give you all of the foundation you need to start writing your own code generators. (If you'd like to review the macro steps, I encourage you to read last month's first-part article, having the same title.)

    Each part of this article approximately covers one of the aforementioned macro steps. As a result, the code is chopped up a bit. To help you successfully build the sample program, a complete, single listing is provided at the end of this article. You should be able to cut and paste the source into a VB.NET module and compile the test unit. To focus our explanation, I will chunk out the individual pieces in the appropriate explanatory section, and then, as mentioned, consolidate the entire listing at the end without comment.

    Creating a CodeCompileUnit

    It helps me to form analogies or equate what I need to learn without what I already know. (Probably pretty much how everyone learns.) The first thing we need to do after we have created our project and add the CodeDOM namespaces—System.CodeDOM and Syste.CodeDOM.Compiler—we need a CodeCompileUnit. The CodeCompileUnit represents the encapsulating class, analogous to a module. The verbiage in the help file refers to the process of generating code as creating a code graph. In the code graph of a code generator, the CodeCompileUnit is the root of the graph. In our example, we declare and create the CodeCompileUnit with a statement such as the following:

    Dim Unit As CodeCompileUnit = New CodeCompileUnit()

    Adding Namespaces

    Namespaces in VB.NET are generally concealed from us in the project properties. They are there, and we need to manually incorporate these into our code generator. In the scheme of things, the namespace is the enclosing entity inside of a module, and we need to create that piece next. In conjunction with defining a namespace, we add our import statements at this point, too. The whole parcel is added to the enclosing CodeCompileUnit.

    We know from experience—or by creating a Windows application from a template—that the namespaces System, System.Drawing, System.Windows.Forms, System.Xml, and System.Data are useful in Windows applications. Collectively, with the namespace we want to add the import statements we'll likely need in a Windows application. The namespace CodeDOM code for our example is:

    Dim Namespaces As CodeNamespace = New CodeNamespace( _ "codeguru.com") Namespaces.Imports.Add( New CodeNamespaceImport("System")) Namespaces.Imports.Add( New CodeNamespaceImport("System.Drawing")) Namespaces.Imports.Add( New CodeNamespaceImport("System. _ Windows.Forms")) Namespaces.Imports.Add( New CodeNamespaceImport("System.Xml")) Namespaces.Imports.Add( New CodeNamespaceImport("System.Data")) Unit.Namespaces.Add(Namespaces)

    Adding Types

    The next logical step in writing object-oriented code is to define our types. This step carries over into our code generator, and we define a type using the CodeTypeDeclaration. The next group of code defines our Form class and adds that class to our codeguru.com namespace.

    Dim MyType As CodeTypeDeclaration = New CodeTypeDeclaration( _ "Form1") MyType.IsClass = True MyType.TypeAttributes = Reflection.TypeAttributes.Public MyType.BaseTypes.Add("System.Windows.Forms.Form") Namespaces.Types.Add(MyType)

    The first statement will ultimately perform substitution and add the lines of code "Class Form1" and "End Class". One facet of the CodeDOM is that if we use the CSharpCodeProvider (instead of the VBCodeProvider), the same statement will generate "class Form1{" and "}", the C# version of a class deifinition.

    The balance of the statements indicate that the type is a class, as opposed to a structure or enumeration, that the class is Public, it inherits from System.Windows.Forms.Form, and adds the type to our namespace. These are all steps that we would perform if we were writing code in the editor. The code substitution performed by this part of our code generator, using a VBCodeProvider, will produce code that looks like this:

    Public Class Form1 Inherits System.Windows.Forms.Form End Class

    Adding Members

    Consistent with our "what would I do next if I were writing the code in the IDE?" theme is to add members to our class. Members means events, fields, properties, enumerations, delegates, nested classes, nested structures, and methods. A Windows Form class uses a constructor, a Dispose method, an IContainer field, and InitializeComponent method and their incumbent lines of code. We'll examine each of these member types and their coincidental CodeDOM code next.

    Defining the Constructor

    The Sub New method—or constructor—in a Windows Form is a public method. All it does in a Form—by default, unless you add code—is to call the InitializeComponent method. We'll follow the framework's lead and generate the lines of code. The next part of our generator takes care of this part of the Form's initialization for us.

    Dim Constructor As CodeConstructor = New CodeConstructor() Constructor.Attributes = MemberAttributes.Public Constructor.Statements.Add( _ New CodeMethodInvokeExpression( _ New CodeThisReferenceExpression(), "InitializeComponent", _ New CodeExpression() {})) MyType.Members.Add(Constructor)

    The first statement creates an instance of a CodeConstructor. In VB.NET, this will generate a Sub New; and in C#, it will generate a constructor with the same name as the class. The next statement establishes our constructor as a public constructor. (We might use a non-public constructor for a Singleton class.) The next monolithic statement is indicative of lines-of-code CodeDOM statements in general; they tend to be verbose. The first object represents a reference to our InitializeComponent method. The next, nested objects represent the pointer-to-self Me, and a call to InitializeComponent with no parameters. The last statement adds the constructor, represented by the CodeConstructor object, to our type. Collectively this code generates:

    Public Sub New() MyBase.New() InitializeComponent() End Sub

    We didn't explicitly write any code to call the parent class' constructor. This was added by the CodeDOM itself.

    Defining the Dispose Method

    The basic form of the Dispose method in a Form is to call Dispose on the container holding all of our components. Knowing the implementation of a reasonable Dispose method from a Form template, we can implement the Dispose generate code as follows:

    1: Dim DisposeMethod As CodeMemberMethod = _ 2: New CodeMemberMethod() 3: 4: DisposeMethod.Name = "Dispose" 5: DisposeMethod.Attributes = _ 6: MemberAttributes.Family Or MemberAttributes. _ Overloaded Or _ 7: MemberAttributes.Override 8: 9: DisposeMethod.Parameters.Add( _ 10: New CodeParameterDeclarationExpression( _ 11: GetType(Boolean), "disposing")) 12: 13: Dim Statement As CodeConditionStatement = _ 14: New CodeConditionStatement() 15: Statement.Condition = _ 16: New CodeArgumentReferenceExpression("disposing") 17: 18: Dim TrueStatement As CodeConditionStatement = _ 19: New CodeConditionStatement() 20: TrueStatement.Condition = _ 21: New CodeBinaryOperatorExpression( _ 22: New CodeArgumentReferenceExpression( _ "components"), _ 23: CodeBinaryOperatorType.IdentityInequality, _ 24: New CodePrimitiveExpression(Nothing)) 25: 26: 27: TrueStatement.TrueStatements.Add( _ 28: New CodeMethodInvokeExpression( _ 29: New CodeFieldReferenceExpression(Nothing, _ "components"), _ 30: "Dispose", New CodeExpression() {})) 31: 32: Statement.TrueStatements.Add(TrueStatement) 33: 34: DisposeMethod.Statements.Add(Statement) 35: 36: DisposeMethod.Statements.Add( _ 37: New CodeMethodInvokeExpression( _ 38: New CodeBaseReferenceExpression(), _ 39: "Dispose", New _ CodeArgumentReferenceExpression() _ 40: {New CodeArgumentReferenceExpression( _ 41: "disposing")})) 42: 43: MyType.Members.Add(DisposeMethod)

    (Line numbers were added for reference due to the length of the listing.) When generated, a Dispose method is only about six lines of code. Clearly, the code to generate this method is much longer. From experience, it seems to take about ten lines of code for every one line of generated code.

    When rendered, Dispose is comprised of a nested If-conditional statement and a call to the base Dispose method. Lines 1 through 7 define the Dispose method body. The settings used for the CodeMemberMethod indicate that Dispose is a Protected (Family), overloaded and overridden method. Lines 9 through 11 indicate that Dispose takes one Boolean argument name disposing, thus ending the method signature. The remaining statements are lines dancing between the bounds of the Dispose method.

    We use the CodeConditionStatement on lines 13 through 16 to create a conditional statement to determine if we are disposing of the Form. Lines 18 through 24 perform the nested test to ensure that the components field has been assigned. Ultimately, such a test has a True and False part. By adding an expression to the TrueStatements collection, we are codifying the generative part of the If half of the statement. Our If-half invokes a call to components.Dispose, passing no arguments as represented by the empty array of CodeExpression objects on line 30. We finish the Dispose method by adding the nested test and the components.Dispose call to our conditional statement (line 32), adding code to our Dispose method (line 24), adding a call to our base Dispose method (lines 36 through 41), and adding the Dispose method to our class (line 43).

    Adding the IContainer Reference

    The components field will be an instance of a class that implements IContainer. Field declarations are relatively simple instances of the CodeMemberField. Here is the statement that declares the components field; the initialization of the container occurs in the InitializeComponent method in the next section.

    MyType.Members.Add( _ New CodeMemberField("System.ComponentModel.IContainer", _ "components"))

    Defining the InitializeComponent Method

    A blank form defines the InitializeComponent method by using the DebuggerStepThrough attribute and creating an instance of an IContainer. (If you were creating a code generator based on this form, you would want to keep a reference to the InitializeComponent method, as this is where you would add code that instantiated nested controls such as Labels and TextBoxes.) As with the Dispose method, line numbers were added for reference only due to the length of the fragment.

    1: Dim InitializeMethod As CodeMemberMethod = _ 2: New CodeMemberMethod() 3: 4: InitializeMethod.name = "InitializeComponent" 5: InitializeMethod.Attributes = MemberAttributes.Private 6: 7: InitializeMethod.CustomAttributes.Add( _ 8: New CodeAttributeDeclaration( _ 9: "System.Diagnostics.DebuggerStepThrough")) 10: 11: InitializeMethod.Statements.Add( _ 12: New CodeAssignStatement( _ 13: New CodeFieldReferenceExpression( _ 14: New CodeThisReferenceExpression(), "components"), _ 15: New CodeObjectCreateExpression( _ 16: New CodeTypeReference( _ 17: GetType(System.ComponentModel.Container)), _ 18: New CodeExpression() {}))) 19: 20: MyType.Members.Add(InitializeMethod)

    Lines 1 and 2 declare a CodeMemberMethod. This class will always represent a method. Lines 4 and 5 name the method and adorn it with the Private access modifier. Lines 7 through 8 attach the System.Diagnostics.DebuggerStepThrough attribute, as an instance of the CodeAttributeDeclaration class, by adding the instance to CodeMemberMethod's CustomAttributes collection. Lines 11 through 18 will generate a code that creates a new instance of System.ComponentModel.Container and assigns that instance to the components field. Let's take a second to decompose all of the inline code.

    Line 11 indicates that we are adding a statement to the CodeMemberMethod's Statements collection. Line 12 creates a new instance of an assignment statement. Line 13 indicates that we will be referring to a field in this class. Line 14 completes the CodeFieldReferenceExpression with Me and components, yielding the code Me.components on the left-hand-side of the assignment. Line 15 begins the right-hand-side of the assignment, indicating that we will be constructing an object. Line 16 indicates a type reference (think, class name) and will generate a constructor call by name to the Container class, passing no arguments. Finally we add the CodeMemberMethod to the graph on line 20.

    Picking a Provider and Generating Code

    We are just about finished at this point. We need to pick a provider. The separation of responsibilities in the CodeDOM means that almost anyone should be able to implement a provider that reads the CodeDOM graph and substitutes it for a specific language. I have used the C# and VB providers, and there are others being implemented or that already exist.

    If we want to generate VB.NET source code, we need a provider, a code generator, and a stream. The generator writes its output to a stream, offering more flexibility than if it only generated code to a file. For example, a string stream would permit the code to be generated directly a string and inserted into the IDE. Here are the statements that write source code from our graph.

    Dim Stream As StreamWriter = New StreamWriter("out.vb") Try Dim Generator As ICodeGenerator = _ (New VBCodeProvider()).CreateGenerator Generator.GenerateCodeFromCompileUnit( _ Unit, Stream, Nothing) Finally Stream.Close() End Try

    The first statement creates an instance of a StreamWriter. The StreamWriter will send our generated code to a file. In the example, the file will be named out.vb. The next statement (after the beginning of the Try..Finally block) declares an instance of an IGenerator, creates a VBCodeProvider, and asks that provider for its code generator. If we needed to, we could keep an instance of the VBCodeProvider by assigning it to a temporary variable defined as an ICodeProvider. The next statement generates the source code, and we finish up by closing the stream. The generated source code is shown in Listing 1.

    Listing 1: The code created by our code generator.

    Option Strict Off Option Explicit On Imports System Imports System.Data Imports System.Drawing Imports System.Windows.Forms Imports System.Xml Namespace codeguru.com Public Class Form1 Inherits System.Windows.Forms.Form Private components As System.ComponentModel.IContainer Public Sub New() MyBase.New Me.InitializeComponent End Sub Protected Overloads Overrides Sub Dispose(ByVal _ disposing As Boolean) If disposing Then If (Not (components) Is Nothing) Then components.Dispose End If End If MyBase.Dispose(disposing) End Sub <System.Diagnostics.DebuggerStepThrough()> _ Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container End Sub End Class End Namespace

    At this point, you might wonder about the .resx file that is associated with forms. As it turns out, if you open this file in the IDE, Visual Studio .NET will generate the resource file for the form. We don't need to explicitly define the .resx file.

    Compiling

    What remains to do is compile our source code and ensure that our generator works correctly. What I specifically like about code generators is that, once perfected, they generate perfect code every single time. No syntax errors. No typographic errors, and no typing. To compile our code, we need to create an ICodeCompiler, specify some compiler options, compile, and then check for errors. Here is the rest of the code generator.

    1: 2: Dim Compiler As ICodeCompiler = _ 3: (New VBCodeProvider()).CreateCompiler() 4: 5: 6: Dim Options As CompilerParameters = _ 7: New CompilerParameters() 8: Options.GenerateExecutable = True 9: Options.OutputAssembly = "test.exe" 10: Options.CompilerOptions = "/target:winexe" 11: Options.MainClass = "codeguru.com.Form1" 12: Options.ReferencedAssemblies.AddRange( _ 13: New String() {"System.dll", "System.Data.dll", _ 14: "System.Drawing.dll", "System.Windows.Forms.dll", _ 15: "System.XML.dll"}) 16: 17: 18: 19: Dim Result As CompilerResults = _ 20: Compiler.CompileAssemblyFromFile(Options, "out.vb") 21: 22: Dim E As CompilerError 23: If (Result.Errors.Count > 0) Then 24: For Each E In Result.Errors 25: Console.WriteLine(E.ErrorText) 26: Next 27: Else 28: Console.WriteLine("compiled successfully") 29: End If 30: Console.WriteLine("press enter to continue") 31: Console.ReadLine()

    Lines 2 and 3 create a VBCodeProvider and request that provider's compiler. Lines 6 through 15 define the CompilerParameters. Line 8 indicates that we want to create an executable, as opposed to a DLL. Line 9 names our output .exe file. Line 10—CompilerOptions—permits us to express additional compiler parameters not represented by a CompilerParameters property. Without line 10, our code would generate a console application that happened to display a Windows Form. Line 11 defines the entry point for our executable as the Form1 code we generated. Finally, lines 12 through 15 include the assemblies we need to reference. Because these assemblies are in the Global Assembly Cache, we can reference them without file path information. Unregistered assemblies not in the local directory probably need path information.

    Lines 19 and 20 compile our source code and assign the CompilerResults to the local Result variable. If there are errors—line 23—the code enumerates each error and writes it to the console. That's it. We're finished. If everything went correctly, there should be a test.exe file in the same directory as the code generator, and running that executable should display a blank form, as shown in Figure 1.

    Figure 1: Our wholly generated form.

    Reference: Complete Listing for the Form Generator

    Imports System.CodeDom Imports System.CodeDom.Compiler Imports System.IO Module Module1 Sub Main() Dim Unit As CodeCompileUnit = New CodeCompileUnit() Dim Namespaces As CodeNamespace = _ New CodeNamespace("codeguru.com") Namespaces.Imports.Add( _ New CodeNamespaceImport("System")) Namespaces.Imports.Add( _ New CodeNamespaceImport("System.Drawing")) Namespaces.Imports.Add( _ New CodeNamespaceImport("System.Windows.Forms")) Namespaces.Imports.Add( _ New CodeNamespaceImport("System.Xml")) Namespaces.Imports.Add( _ New CodeNamespaceImport("System.Data")) Unit.Namespaces.Add(Namespaces) Dim MyType As CodeTypeDeclaration = _ New CodeTypeDeclaration("Form1") MyType.IsClass = True MyType.TypeAttributes = Reflection.TypeAttributes.Public MyType.BaseTypes.Add("System.Windows.Forms.Form") Namespaces.Types.Add(MyType) Dim Constructor As CodeConstructor = _ New CodeConstructor() Constructor.Attributes = MemberAttributes.Public Constructor.Statements.Add( _ New CodeMethodInvokeExpression( _ New CodeThisReferenceExpression(), _ "InitializeComponent", New CodeExpression() {})) MyType.Members.Add(Constructor) MyType.Members.Add( _ New CodeMemberField("System.ComponentModel. _ IContainer", "components")) Dim DisposeMethod As CodeMemberMethod = _ New CodeMemberMethod() DisposeMethod.Name = "Dispose" DisposeMethod.Attributes = _ MemberAttributes.Family Or MemberAttributes.Overloaded _ Or MemberAttributes.Override DisposeMethod.Parameters.Add( _ New CodeParameterDeclarationExpression( _ GetType(Boolean), "disposing")) Dim Statement As CodeConditionStatement = _ New CodeConditionStatement() Statement.Condition = _ New CodeArgumentReferenceExpression("disposing") Dim TrueStatement As CodeConditionStatement = _ New CodeConditionStatement() TrueStatement.Condition = _ New CodeBinaryOperatorExpression( _ New CodeArgumentReferenceExpression("components"), _ CodeBinaryOperatorType.IdentityInequality, _ New CodePrimitiveExpression(Nothing)) TrueStatement.TrueStatements.Add( _ New CodeMethodInvokeExpression( _ New CodeFieldReferenceExpression(Nothing, _ "components"), "Dispose", New _ CodeExpression() {})) Statement.TrueStatements.Add(TrueStatement) DisposeMethod.Statements.Add(Statement) DisposeMethod.Statements.Add( _ New CodeMethodInvokeExpression( _ New CodeBaseReferenceExpression(), _ "Dispose", New CodeArgumentReferenceExpression() _ {New CodeArgumentReferenceExpression( _ "disposing")})) MyType.Members.Add(DisposeMethod) Dim InitializeMethod As CodeMemberMethod = _ New CodeMemberMethod() InitializeMethod.name = "InitializeComponent" InitializeMethod.Attributes = MemberAttributes.Private InitializeMethod.CustomAttributes.Add( _ New CodeAttributeDeclaration( _ "System.Diagnostics.DebuggerStepThrough")) InitializeMethod.Statements.Add( _ New CodeAssignStatement( _ New CodeFieldReferenceExpression( _ New CodeThisReferenceExpression(), "components"), _ New CodeObjectCreateExpression( _ New CodeTypeReference( _ GetType(System.ComponentModel.Container)), _ New CodeExpression() {}))) MyType.Members.Add(InitializeMethod) Dim Stream As StreamWriter = New StreamWriter("out.vb") Try Dim Generator As ICodeGenerator = _ (New VBCodeProvider()).CreateGenerator Generator.GenerateCodeFromCompileUnit( _ Unit, Stream, Nothing) Finally Stream.Close() End Try Dim Compiler As ICodeCompiler = _ (New VBCodeProvider()).CreateCompiler() Dim Options As CompilerParameters = _ New CompilerParameters() Options.GenerateExecutable = True Options.OutputAssembly = "test.exe" Options.CompilerOptions = "/target:winexe" Options.MainClass = "codeguru.com.Form1" Options.ReferencedAssemblies.AddRange( _ New String() {"System.dll", "System.Data.dll", _ "System.Drawing.dll", "System.Windows.Forms.dll", _ "System.XML.dll"}) Dim Result As CompilerResults = _ Compiler.CompileAssemblyFromFile(Options, "out.vb") Dim E As CompilerError If (Result.Errors.Count > 0) Then For Each E In Result.Errors Console.WriteLine(E.ErrorText) Next Else Console.WriteLine("compiled successfully") End If Console.WriteLine("press enter to continue") Console.ReadLine() End Sub End Module

    Summary

    When some people see the CodeDOM, they say, "Oh, that's easy; it's just code substitution." Yes, at its essence it is substitution, and poetry and songs are just words and notes. Yet, the important part is that it is the orchestration of phrases and notes that create vocabulary that enables humans to be more expressive, and it is the captured classes in the CodeDOM that will likely be an invaluable step that enables programmers to create more expressive software. The CodeDOM is a stepping stone that enhances expressivity just as music and poetry enhance their respective art forms.

    The power of code generators will come as we create higher and higher level constructs. The CodeDOM seems to be experiencing a period of infancy. However, as bigger, more complex aggregates evolve, we will be able to generate increasingly complex chunks of code. This in no way should diminish the number of programmers we will need; what it will do is provide programmers with a greater vocabulary to draw from and enable us to build more advanced systems while eliminating tedious, automatable chores.

    About the Author

    Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. Look for his upcoming book, Visual Basic .NET Power Coding, from Addison-Wesley. Paul Kimmel is available to help design and build your .NET solutions and can be contacted at pkimmel@softconcepts.com.

    # # #







    For assignment of letters to disk file systems, see Drive letter assignment.

    In computer programming, an assignment statement sets and/or re-sets the value stored in the storage location(s) denoted by a variablename; in other words, it copies a value into the variable. In most imperativeprogramming languages, the assignment statement (or expression) is a fundamental construct.

    Today, the most commonly used notation for this basic operation has come to be (originally Superplan 1949–51, popularized by Fortran 1957 and C) followed by [1] (originally ALGOL 1958, popularised by Pascal),[2] although there are many other notations in use. In some languages the symbol used is regarded as an operator (meaning that the assignment has a value) while others define the assignment as a statement (meaning that it cannot be used in an expression).

    Assignments typically allow a variable to hold different values at different times during its life-span and scope. However, some languages (primarily strictly functional) do not allow that kind of "destructive" reassignment, as it might imply changes of non-local state. The purpose is to enforce referential transparency, i.e. functions that do not depend on the state of some variable(s), but produce the same results for a given set of parametric inputs at any point in time. Modern programs in other languages also often use similar strategies, although less strict, and only in certain parts, in order to reduce complexity, normally in conjunction with complementing methodologies such as data structuring, structured programming and object orientation.

    Semantics[edit]

    An assignment operation is a process in imperative programming in which different values are associated with a particular variable name as time passes.[1] The program, in such model, operates by changing its state using successive assignment statements.[2][3] Primitives of imperative programming languages rely on assignment to do iteration.[4] At the lowest level, assignment is implemented using machine operations such as or .[2][4]

    Variables are containers for values. It is possible to put a value into a variable and later replace it with a new one. An assignment operation modifies the current state of the executing program.[3] Consequently, assignment is dependent on the concept of variables. In an assignment:

    • The is evaluated in the current state of the program.
    • The is assigned the computed value, replacing the prior value of that variable.

    Example: Assuming that is a numeric variable, the assignment means that the content of the variable is doubled after the execution of the statement.

    An example segment of C code:

    intx=10;floaty;x=23;y=32.4f;

    In this sample, the variable is first declared as an int, and is then assigned the value of 10. Notice that the declaration and assignment occur in the same statement. In the second line, is declared without an assignment. In the third line, is reassigned the value of 23. Finally, is assigned the value of 32.4.

    For an assignment operation, it is necessary that the value of the is well-defined (it is a valid rvalue) and that the represents a modifiable entity (it is a valid modifiable (non-const) lvalue). In some languages, typically dynamic ones, it is not necessary to declare a variable prior to assigning it a value.

    Single assignment[edit]

    See also: Static single assignment form

    Any assignment that changes an existing value (e.g. ) is disallowed in purely functional languages.[4] In functional programming, assignment is discouraged in favor of single assignment, also called initialization. Single assignment is an example of name binding and differs from assignment as described in this article in that it can only be done once, usually when the variable is created; no subsequent reassignment is allowed.

    An evaluation of expression does not have a side effect if it does not change an observable state of the machine,[5] and produces same values for same input.[4] Imperative assignment can introduce side effects while destroying and making the old value unavailable while substituting it with a new one,[6] and is referred to as destructive assignment for that reason in LISP and functional programming, similar to destructive updating.

    Single assignment is the only form of assignment available in purely functional languages, such as Haskell, which do not have variables in the sense of imperative programming languages[4] but rather named constant values possibly of compound nature with their elements progressively defined on-demand. Purely functional languages can provide an opportunity for computation to be performed in parallel, avoiding the von Neumann bottleneck of sequential one step at time execution, since values are independent of each other.[7]

    Impure functional languages provide both single assignment as well as true assignment (though true assignment is typically used with less frequency than in imperative programming languages). For example, in Scheme, both single assignment (with ) and true assignment (with ) can be used on all variables, and specialized primitives are provided for destructive update inside lists, vectors, strings, etc. In OCaml, only single assignment is allowed for variables, via the syntax; however destructive update can be used on elements of arrays and strings with separate operator, as well as on fields of records and objects that have been explicitly declared mutable (meaning capable of being changed after their initial declaration) by the programmer.

    Functional programming languages that use single assignment include Clojure (for data structures, not vars), Erlang (it accepts multiple assignment if the values are equal, in contrast to Haskell), F#, Haskell, Lava, OCaml, Oz (for dataflow variables, not cells), Racket (for some data structures like lists, not symbols), SASL, Scala (for vals), SISAL, Standard ML. Non-backtrackingProlog code can be considered explicit single-assignment, explicit in a sense that its (named) variables can be in explicitly unassigned state, or be set exactly once. In Haskell, by contrast, there can be no unassigned variables, and every variable can be thought of as being implicitly set to its value (or rather to a computational object that will produce its value on demand) when it is created.

    Value of an assignment[edit]

    In some programming languages, an assignment statement returns a value, while in others it does not.

    In most expression-oriented programming languages (for example, C), the assignment statement returns the assigned value, allowing such idioms as , in which the assignment statement returns the value of , which is then assigned to . In a statement such as , the return value of a function is used to control a loop while assigning that same value to a variable.

    In other programming languages, Scheme for example, the return value of an assignment is undefined and such idioms are invalid.

    In Haskell,[8] there is no variable assignment; but operations similar to assignment (like assigning to a field of an array or a field of a mutable data structure) usually evaluate to the unit type, which is represented as . This type has only one possible value, therefore containing no information. It is typically the type of an expression that is evaluated purely for its side effects.

    Variant forms of assignment[edit]

    Certain use patterns are very common, and thus often have special syntax to support them. These are primarily syntactic sugar to reduce redundancy in the source code, but can also simplify compilation by clarifying the programmer's intent and easing analysis of the source code.

    Augmented assignment[edit]

    Main article: Augmented assignment

    The case where the assigned value depends on a previous one is so common that many imperative languages, most notably C and the majority of its descendants, provide special operators called augmented assignment, like , so can instead be written as .[3] Beyond syntactic sugar, this simplifies compilation, since it makes it clear that in-place modification of the variable is possible.

    Chained assignment[edit]

    A statement like is called a chained assignment in which the value of is assigned to multiple variables and . Chained assignments are often used to initialize multiple variables, as in

    Not all programming languages support chained assignment. Chained assignments are equivalent to a sequence of assignments, but the evaluation strategy differs between languages. For simple chained assignments, like initializing multiple variables, the evaluation strategy does not matter, but if the targets (l-values) in the assignment are connected in some way, the evaluation strategy affects the result.

    In some programming languages (C for example), chained assignments are supported because assignments are expressions, and have values. In this case chain assignment can be implemented by having a right-associative assignment, and assignments happen right-to-left. For example, is equivalent to . In C++ they are also available for values of class types by declaring the appropriate return type for the assignment operator.

    In Python, assignment statements are not expressions and thus do not have a value. Instead, chained assignments are a series of statements with multiple targets for a single expression. The assignments are executed left-to-right so that evaluates the expression , then assigns the result to the leftmost target, , and then assigns the same result to the next target, , using the new value of .[9] This is essentially equivalent to though no actual variable is produced for the temporary value.

    Parallel assignment[edit]

    Some programming languages, such as APL, Go,[10]JavaScript (since 1.7), PHP, Maple, Lua, occam 2,[11]Perl,[12]Python,[13]REBOL, Ruby,[14] and Windows PowerShell allow several variables to be assigned in parallel, with syntax like:

    a, b := 0, 1

    which simultaneously assigns 0 to and 1 to . This is most often known as parallel assignment; it was introduced in CPL in 1963, under the name simultaneous assignment,[15] and is sometimes called multiple assignment, though this is confusing when used with "single assignment", as these are not opposites. If the right-hand side of the assignment is a single variable (e.g. an array or structure), the feature is called unpacking[16] or destructuring assignment:[17]

    var list := {0, 1} a, b := list

    The list will be unpacked so that 0 is assigned to and 1 to . More interestingly,

    a, b := b, a

    swaps the values of and . In languages without parallel assignment, this would have to be written to use a temporary variable

    var t := a a := b b := t

    since leaves both and with the original value of .

    Some languages, such as Go and Python, combine parallel assignment, tuples, and automatic tuple unpacking to allow multiple return values from a single function, as in this Python example:

    deff():return1,2a,b=f()

    This provides an alternative to the use of output parameters for returning multiple values from a function. This dates to CLU (1974), and CLU helped popularize parallel assignment generally.

    In C and C++, the comma operator is similar to parallel assignment in allowing multiple assignments to occur within a single statement, writing instead of . This is primarily used in for loops, and is replaced by parallel assignment in other languages such as Go.[18] However, the above C++ code does not ensure perfect simultaneity, since the right side of the following code is evaluated after the left side. In languages such as Python, will assign the two variables concurrently, using the initial value of a to compute the new b.

    Assignment versus equality[edit]

    See also: Relational operator § Confusion with assignment operators

    The use of the equals sign as an assignment operator has been frequently criticized, due to the conflict with equals as comparison for equality. This results both in confusion by novices in writing code, and confusion even by experienced programmers in reading code. The use of equals for assignment dates back to Heinz Rutishauser's language Superplan, designed from 1949 to 1951, and was particularly popularized by Fortran:

    A notorious example for a bad idea was the choice of the equal sign to denote assignment. It goes back to Fortran in 1957[a] and has blindly been copied by armies of language designers. Why is it a bad idea? Because it overthrows a century old tradition to let “=” denote a comparison for equality, a predicate which is either true or false. But Fortran made it to mean assignment, the enforcing of equality. In this case, the operands are on unequal footing: The left operand (a variable) is to be made equal to the right operand (an expression). x = y does not mean the same thing as y = x.[19]

    — Niklaus Wirth, Good Ideas, Through the Looking Glass

    Beginning programmers sometimes confuse assignment with the relational operator for equality, as "=" means equality in mathematics, and is used for assignment in many languages. But assignment alters the value of a variable, while equality testing tests whether two expressions have the same value.

    In some languages, such as BASIC, a single equals sign () is used for both the assignment operator and the equality relational operator, with context determining which is meant. Other languages use different symbols for the two operators. For example:

    • In Pascal, the assignment operator is a colon and an equals sign () while the equality operator is a single equals ().
    • In C, the assignment operator is a single equals sign () while the equality operator is a pair of equals signs ().
    • In R, the assignment operator is basically , as in , but a single equals sign can be used in certain contexts.

    The similarity in the two symbols can lead to errors if the programmer forgets which form ("", "", "") is appropriate, or mistypes "" when "" was intended. This is a common programming problem with languages such as C (including one famous attempt to backdoor the Linux kernel [20]), where the assignment operator also returns the value assigned (in the same way that a function returns a value), and can be validly nested inside expressions. If the intention was to compare two values in an statement, for instance, an assignment is quite likely to return a value interpretable as Boolean true, in which case the clause will be executed, leading the program to behave unexpectedly. Some language processors (such as gcc) can detect such situations, and warn the programmer of the potential error.

    Notation[edit]

    See also: Comparison of programming languages (variable and constant declarations)

    The two most common representations for the copying assignment are equals sign () and colon-equals (). Both forms may semantically denote either an assignment statement or an assignment operator (which also has a value), depending on language and/or usage.

    Fortran, PL/I, C (and descendants such as C++, Java, etc.), Bourne shell, Python, Go (assignment to pre-declared variables), R, Windows PowerShell, etc.
    ALGOL (and derivatives), Simula, CPL, BCPL, Pascal[21] (and descendants such as Modula), Mary, PL/M, Ada, Smalltalk, Eiffel,[22][23]Oberon, Dylan,[24]Seed7, Go (shorthand for declaring and defining a variable),[25]Io, AMPL, ML,[26] etc.

    Other possibilities include a left arrow or a keyword, though there are other, rarer, variants:

    Mathematical pseudo code assignments are generally depicted with a left-arrow.

    Some platforms put the expression on the left and the variable on the right:

    Some expression-oriented languages, such as Lisp[28][29] and Tcl, uniformly use prefix (or postfix) syntax for all statements, including assignment.

    See also[edit]

    Notes[edit]

    References[edit]

    1. ^ abTopics in Information Processing
    2. ^ abcImperative Programming
    3. ^ abcRuediger-Marcus Flaig (2008). Bioinformatics programming in Python: a practical course for beginners. Wiley-VCH. pp. 98–99. ISBN 978-3-527-32094-3. Retrieved 25 December 2010. 
    4. ^ abcdeCrossing borders: Explore functional programming with HaskellArchived November 19, 2010, at the Wayback Machine., by Bruce Tate
    5. ^Mitchell, John C. (2003). Concepts in programming languages. Cambridge University Press. p. 23. ISBN 978-0-521-78098-8. Retrieved 3 January 2011. 
    6. ^Imperative Programming Languages (IPL)
    7. ^John C. Mitchell (2003). Concepts in programming languages. Cambridge University Press. pp. 81–82. ISBN 978-0-521-78098-8. Retrieved 3 January 2011. 
    8. ^Hudak, Paul (2000). The Haskell School of Expression: Learning Functional Programming Through Multimedia. Cambridge: Cambridge University Press. ISBN 0-521-64408-9. 
    9. ^https://docs.python.org/reference/simple_stmts.html#assignment-statements
    10. ^The Go Programming Language Specification: Assignments
    11. ^INMOS Limited, ed. (1988). Occam 2 Reference Manual. New Jersey: Prentice Hall. ISBN 0-13-629312-3. 
    12. ^Wall, Larry; Christiansen, Tom; Schwartz, Randal C. (1996). Perl Programming Language (2 ed.). Cambridge: O´Reilly. ISBN 1-56592-149-6. 
    13. ^Lutz, Mark (2001). Python Programming Language (2 ed.). Sebastopol: O´Reilly. ISBN 0-596-00085-5. 
    14. ^Thomas, David; Hunt, Andrew (2001). Programming Ruby: The Pragmatic Programmer's Guide. Upper Saddle River: Addison Wesley. ISBN 0-201-71089-7. 
    15. ^D.W. Barron et al., "The main features of CPL", Computer Journal6:2:140 (1963). full text (subscription)
    16. ^http://legacy.python.org/dev/peps/pep-3132/
    17. ^https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
    18. ^Effective Go: for, "Finally, Go has no comma operator and ++ and -- are statements not expressions. Thus if you want to run multiple variables in a for you should use parallel assignment (although that precludes ++ and --)."
    19. ^Niklaus Wirth. "Good Ideas, Through the Looking Glass". CiteSeerX 10.1.1.88.8309. 
    20. ^Corbet (6 November 2003). "An attempt to backdoor the kernel". 
    21. ^Moore, Lawrie (1980). Foundations of Programming with Pascal. New York: John Wiley & Sons. ISBN 0-470-26939-1. 
    22. ^Meyer, Bertrand (1992). Eiffel the Language. Hemel Hempstead: Prentice Hall International(UK). ISBN 0-13-247925-7. 
    23. ^Wiener, Richard (1996). An Object-Oriented Introduction to Computer Science Using Eiffel. Upper Saddle River, New Jersey: Prentice Hall. ISBN 0-13-183872-5. 
    24. ^Feinberg, Neal; Keene, Sonya E.; Mathews, Robert O.; Withington, P. Tucker (1997). Dylan Programming. Massachusetts: Addison Wesley. ISBN 0-201-47976-1. 
    25. ^The Go Programming Language Specification: short variable declarations
    26. ^Ullman, Jeffrey D. (1998). Elements of ML Programming: ML97 Edition. Englewood Cliffs, New Jersey: Prentice Hall. ISBN 0-13-790387-1. 
    27. ^Iverson, Kenneth E. (1962). A Programming Language. John Wiley and Sons. ISBN 0-471-43014-5. 
    28. ^Graham, Paul (1996). ANSI Common Lisp. New Jersey: Prentice Hall. ISBN 0-13-370875-6. 
    29. ^Steele, Guy L. (1990). Common Lisp: The Language. Lexington: Digital Press. ISBN 1-55558-041-6. 
    30. ^Dybvig, R. Kent (1996). The Scheme Programming Language: ANSI Scheme. New Jersey: Prentice Hall. ISBN 0-13-454646-6. 
    31. ^Smith, Jerry D. (1988). Introduction to Scheme. New Jersey: Prentice Hall. ISBN 0-13-496712-7. 
    32. ^Abelson, Harold; Sussman, Gerald Jay; Sussman, Julie (1996). Structure and Interpretation of Computer Programs. New Jersey: McGraw-Hill. ISBN 0-07-000484-6. 
    1. ^Use of predates Fortran, though it was popularized by Fortran.

    0 thoughts on “Codedom Variable Assignments”

      -->

    Leave a Comment

    Your email address will not be published. Required fields are marked *