Skip to content

String Representation

String Representation#

String representation is a method that defines how an object should be converted to a string format for display, debugging, or logging purposes. It provides a human-readable textual representation of an object's state and essential characteristics.

Without proper string representation, objects typically display only their memory address or type information (like Guitar@1a2b3c4d), making debugging and logging sessions frustrating and uninformative.

Without String Representation#

graph TD
    A["Object Instance"] --> B["Default toString()"]
    B --> C["Guitar@1a2b3c4d"]
    B --> D["Object@hashCode()"]

    style A fill:#ffcdd2
    style B fill:#ffcdd2
    style C fill:#ffcdd2
    style D fill:#ffcdd2

With String Representation#

graph TD
    A["Object Instance"] --> B["Custom toString()"]
    B --> C["Guitar{brand='Martin', model='D-28', tuning='Standard'}"]

    style A fill:#c8e6c9
    style B fill:#c8e6c9
    style C fill:#c8e6c9

Key Benefits#

graph TD
    A["String Representation"] --> B["Debugging"]
    A --> C["Logging"]
    A --> D["Testing"]
    A --> E["User Interface"]

    B --> B1["Clear object state"]
    C --> C1["Meaningful log entries"]
    D --> D1["Better test messages"]
    E --> E1["Human-readable display"]

    style A fill:#e3f2fd
    style B fill:#e8f5e8
    style C fill:#e8f5e8
    style D fill:#e8f5e8
    style E fill:#e8f5e8

Best Practices#

  • Include essential object properties
  • Use consistent formatting
  • Keep output concise but informative
  • Avoid sensitive information (passwords, tokens)

Let's see how different languages implement string representation:

In Java, the toString method is inherited from the Object class and can be overridden to provide custom string representation.

public class Guitar {
    private String brand;
    private String model;
    private String tuning;

    public Guitar(String brand, String model, String tuning) {
        this.brand = brand;
        this.model = model;
        this.tuning = tuning;
    }

    @Override
    public String toString() {
        return "Guitar{brand='" + brand + "', model='" + model + "', tuning='" + tuning + "'}";
    }
}

Guitar guitar = new Guitar("Martin", "D-28", "Standard");
System.out.println(guitar); // Output: Guitar{brand='Martin', model='D-28', tuning='Standard'}

In Kotlin, the toString method can be overridden to provide custom string representation, and data classes automatically generate it.

class Guitar(val brand: String, val model: String, val tuning: String) {
    override fun toString(): String {
        return "Guitar{brand='$brand', model='$model', tuning='$tuning'}"
    }
}

// Data class automatically generates toString
data class GuitarData(val brand: String, val model: String, val tuning: String)

val guitar = Guitar("Gibson", "Les Paul", "Drop D")
val guitarData = GuitarData("Fender", "Stratocaster", "Standard")
println(guitar) // Output: Guitar{brand='Gibson', model='Les Paul', tuning='Drop D'}
println(guitarData) // Output: GuitarData(brand=Fender, model=Stratocaster, tuning=Standard)

In TypeScript, the toString method can be overridden to provide custom string representation.

class Guitar {
    constructor(private brand: string, private model: string, private tuning: string) {}

    toString(): string {
        return `Guitar{brand='${this.brand}', model='${this.model}', tuning='${this.tuning}'}`;
    }
}

const guitar = new Guitar("Taylor", "814ce", "DADGAD");
console.log(guitar.toString()); // Output: Guitar{brand='Taylor', model='814ce', tuning='DADGAD'}
console.log(`${guitar}`); // Output: Guitar{brand='Taylor', model='814ce', tuning='DADGAD'}

In Dart, the toString method can be overridden to provide custom string representation.

class Guitar {
    final String brand;
    final String model;
    final String tuning;

    Guitar(this.brand, this.model, this.tuning);

    @override
    String toString() {
        return 'Guitar{brand=\'$brand\', model=\'$model\', tuning=\'$tuning\'}';
    }
}

void main() {
    Guitar guitar = Guitar("Yamaha", "FG830", "Open G");
    print(guitar); // Output: Guitar{brand='Yamaha', model='FG830', tuning='Open G'}
}

In Swift, the CustomStringConvertible protocol can be implemented to provide custom string representation.

class Guitar: CustomStringConvertible {
    let brand: String
    let model: String
    let tuning: String

    init(brand: String, model: String, tuning: String) {
        self.brand = brand
        self.model = model
        self.tuning = tuning
    }

    var description: String {
        return "Guitar{brand='\(brand)', model='\(model)', tuning='\(tuning)'}"
    }
}

let guitar = Guitar(brand: "PRS", model: "Custom 24", tuning: "Drop C")
print(guitar) // Output: Guitar{brand='PRS', model='Custom 24', tuning='Drop C'}

In Python, the __str__ method can be overridden to provide custom string representation.

class Guitar:
    def __init__(self, brand: str, model: str, tuning: str):
        self.brand = brand
        self.model = model
        self.tuning = tuning

    def __str__(self) -> str:
        return f"Guitar{{brand='{self.brand}', model='{self.model}', tuning='{self.tuning}'}}"

guitar = Guitar("Ibanez", "RG550", "7-String Standard")
print(guitar) # Output: Guitar{brand='Ibanez', model='RG550', tuning='7-String Standard'}
print(str(guitar)) # Output: Guitar{brand='Ibanez', model='RG550', tuning='7-String Standard'}