I'm going to use C# as an example.
Classes are always by reference and structs are always by value, so hopefully this will shine light on exactly what it means.
using System;
// classes in C# are always Pass-By-Reference
public class Foo { public int i; }
// structs in C# can be either Pass-By-Value or Pass-By-Reference
// This includes basic types like `char`, `int`, `double`, etc.
public struct Bar { public int i; }
public class Example {
// Pass-By-Reference is the only way to operate with a class in C#
public static void DoThing(Foo arg) { arg.i = 42; }
// Pass-By-Value is the default way to operate with structs...
public static void DoThing(Bar arg) { arg.i = 42; }
// ...But you can also pass-by-value. The `ref` keyword before the type
// makes this method explicitly operate on a reference instead of a value
public static void DoThingRef(ref Bar arg) { arg.i = 42; }
public static void DoThingRef(ref int arg) { arg = 100; }
public static void Main() {
var byRef = new Foo();
var byVal = new Bar();
byRef.i = 10;
byVal.i = 10;
// Both items now hold a int value of 10
Console.WriteLine($"ByReference: {byRef.i}\nByValue: {byVal.i}");
Console.WriteLine($"\n\nCalling normal functions...\n\n");
// P A S S B Y V A L U E :
// When an argument is passed by value, a copy of the argument is passed into the function.
// This means that rather than the original data, the function recieves new, separate data.
// If any changes are made to that data inside the function, they are applied to the copy, and no changes are made to the original data.
DoThing(byVal);
// P A S S B Y R E F E R E N C E :
// When an argument is passed by reference, the location of the argument is passed into the function.
// This means the function gets the actual thing, as opposed to a copy, as when passed by value.
// Any changes that are made to the argument inside the function, affect the original data.
DoThing(byRef);
// Now, byVal.i is still 10, but byRef.i has changed to 42
Console.WriteLine($"ByReference: {byRef.i}\nByValue: {byVal.i}");
Console.WriteLine($"\n\nCalling `ref Bar` function...\n\n");
// C# does have a way to pass a reference to a struct, but you need to define your function specifically for it.
DoThingRef(ref byVal); // Actually passes reference, `ref` keyword required.
// Now, byVal.i is actually changed to 42.
Console.WriteLine($"ByValue: {byVal.i}");
Console.WriteLine($"\n\nCalling `ref int` function...\n\n");
// We can also directly pass a reference to the int inside of the struct:
DoThingRef(ref byVal.i); // Passes the reference to the i variable of the struct
// Now, byVal.i is changed to 100
Console.WriteLine($"ByValue: {byVal.i}");
}
}
I hope that this helps.