How to create private variables in Dart?

Dart

Dart Problem Overview


I want to create a private variable but I cannot.

Here is my code:

void main() {
  var b = new B();
  b.testB();    
}

class A {
  int _private = 0;

  testA() {
    print('int value: $_private');
    _private = 5;
  }
}

class B extends A {
  String _private;

  testB() {
    _private = 'Hello';
    print('String value: $_private');
    testA();
    print('String value: $_private');
  }
}

When I run this code, I get the following result:

String value: Hello
int value: Hello
Breaking on exception: type 'int' is not a subtype of type 'String' of 'value'.

Also I not get any error or warnings when editing this source code.

How can I create a private variable in Dart?

Dart Solutions


Solution 1 - Dart

From Dart documentation:

> Unlike Java, Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its library.

Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore _ are visible only inside the library.

A few words about libraries:

>> Every Dart app is a library, even if it doesn’t use a library directive. The import and library directives can help you create a modular and shareable code base.

You may have heard of the part directive, which allows you to split a library into multiple Dart files.

Solution 2 - Dart

Privacy in Dart exists at the library, rather than the class level.

If you were to put class A into a separate library file (eg, other.dart), such as:

library other;

class A {
  int _private = 0;

  testA() {
    print('int value: $_private');  // 0
    _private = 5;
    print('int value: $_private'); // 5
  }
}

and then import it into your main app, such as:

import 'other.dart';

void main() {
  var b = new B();
  b.testB();    
}


class B extends A {
  String _private;

  testB() {
    _private = 'Hello';
    print('String value: $_private'); // Hello
    testA();
    print('String value: $_private'); // Hello
  }
}

You get the expected output:

String value: Hello
int value: 0
int value: 5
String value: Hello

Solution 3 - Dart

In dart '_' is used before the variable name to declare it as private. Unlike other programming languages, here private doesn't mean it is available only to the class it is in, private means it is accessible in the file it is in and not accessible to other files.

Solution 4 - Dart

The top answer as of now is definitely correct.

I'll try to go into more detail in this answer.

I'll answer the question, but lead with this: That's just not how Dart is intended to be written, partly because library-private members make it easier to define operators like ==. (Private variables of a second object couldn't be seen for the comparison.)

Now that we've got that out of the way, I'll start out by showing you how it's meant to be done (library-private instead of class-private), and then show you how to make a variable class-private if you still really want that. Here we go.

If one class has no business seeing variables on another class, you might ask yourself whether they really belong in the same library:

    //This should be in a separate library from main() for the reason stated in the main method below.

    class MyClass {
      //Library private variable
      int _val = 0;

      int get val => _val;
      set val(int v) => _val = (v < 0) ? _val : v;
    
      MyClass.fromVal(int val) : _val = val;
    }

    void main() {
      MyClass mc = MyClass.fromVal(1);
      mc.val = -1;
      print(mc.val); //1

      //main() MUST BE IN A SEPARATE LIBRARY TO 
      //PREVENT MODIFYING THE BACKING FIELDS LIKE:
      mc._val = 6;
      print(mc.val); //6
    }

That should be good. However if you really want private class data:

Though you technically aren't allowed to create private variables, you could emulate it using the following closure technique.

(HOWEVER, you should CAREFULLY consider whether you really need it and whether there is a better, more Dart-like way to do what you're trying to accomplish!)

    //A "workaround" that you should THINK TWICE before using because:
    //1. The syntax is verbose.
    //2. Both closure variables and any methods needing to access
    //   the closure variables must be defined inside a base constructor.
    //3. Those methods require typedefs to ensure correct signatures.

    typedef int IntGetter();
    typedef void IntSetter(int value);
    
    class MyClass {
      IntGetter getVal;
      IntSetter setVal;

      MyClass.base() {
        //Closure variable
        int _val = 0;
    
        //Methods defined within constructor closure
        getVal = ()=>_val;
        setVal = (int v) => _val = (v < 0) ? _val : v;
      }

      factory MyClass.fromVal(int val) {
        MyClass result = MyClass.base();
        result.setVal(val);
        return result;
      }
    }

    void main() {
      MyClass mc = MyClass.fromVal(1);
      mc.setVal(-1); //Fails
      print(mc.getVal());
        
      //On the upside, you can't access _val
      //mc._val = 6; //Doesn't compile.
    }

So yeah. Just be careful and try to follow the language's best-practices and you should be fine.

EDIT

Apparently there's a new typedef syntax that's preferred for Dart 2. If you're using Dart 2 you should use that. Or, even better, use inline function types.

If you use the second, it will be less verbose, but the other problems remain.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2553310View Question on Stackoverflow
Solution 1 - DartmezoniView Answer on Stackoverflow
Solution 2 - DartChris BuckettView Answer on Stackoverflow
Solution 3 - DartBensalView Answer on Stackoverflow
Solution 4 - DartAaronFView Answer on Stackoverflow