I am using select2 4.0.3 in the following manner:
       <div class="form-group" >
            <select class="form-control course" id="id_populate_course_categories"                name="course">
                 <option value="-1" selected="selected">Select an option</option>
           </select>
        </div>
And my js is as follows: 
$("#id_populate_course_categories").select2({
    placeholder: {
        id: "-1",
        placeholder: "Select an option"
      },
    allowClear: true,
    ajax: {
        url: "populate/course/categories/",
        dataType: 'json',
        delay: 0,
        data: function (params) {
            return {
                q: params.term, // search term
                page: $('input[name=level]:checked').val(),
            };
        },
        processResults: function (data, params) {
            // parse the results into the format expected by Select2
            // since we are using custom formatting functions we do not need to
            // alter the remote JSON data, except to indicate that infinite
            // scrolling can be used
            params.page = params.page || 1;
            return {
                results: data,
                pagination: {
                    more: (params.page * 30) < data.total_count
                }
            };
        },
        cache: true
    },
    escapeMarkup: function (markup) {
        return markup;
    },
    "language": {
       "noResults": function(){
           return "No Courses Found. Try Another Query? ";
       }
    },
    minimumInputLength: 3,
    templateResult: formatCourseCategory,
    templateSelection: formatCourseCategorySelection,
}).on("change", function (e) {
    var option_chosen = $("#select2-id_populate_course_categories-container").text();
    $("input[name='course_type']").val(option_chosen);
    console.log($(this).text());
    // $('select[name=q_exm]').empty().append('<option value="0">Your Qualifying Exam?</option>');
    // $('input[name="q_exm_score"]').hide();
    // populate_qualifying_exam(course_option_chosen = option_chosen)
});
I have been unable to make the placeholder show and have tried every possible option. I am adding the placeholder exactly as demonstrated in the 4.0.3 release notes, and yet unable to make it work.
Hey! I found a solution, and am adding it just in case some else faces this issue.
Basically, the SO answer here: http://stackoverflow.com/questions/30302329/select2-4-0-placeholder-undefined
helped me, looking at this jsfiddle: https://jsfiddle.net/xqhp0z0x/1/
In my code, templateSelection pointed to function formatCourseCategorySelection, which was this:
function formatCourseCategorySelection(repo) {
    return repo.name
}
changing this to
function formatCourseCategorySelection(repo) {
    return repo.full_name || repo.text;
}
worked.
I believe this is only applicable for select2 4.0.0 and onwards. Also, version 4 does not need an empty option in the select element, as opposed to previous releases. ( they couldn't have possible made this any more difficult to learn )